diff --git a/node_modules/.package-lock.json b/node_modules/.package-lock.json
index 191f9baa..245bd98e 100644
--- a/node_modules/.package-lock.json
+++ b/node_modules/.package-lock.json
@@ -58,9 +58,9 @@
}
},
"node_modules/brace-expansion": {
- "version": "5.0.5",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz",
- "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==",
+ "version": "5.0.6",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz",
+ "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==",
"license": "MIT",
"dependencies": {
"balanced-match": "^4.0.2"
@@ -94,9 +94,9 @@
}
},
"node_modules/nodemailer": {
- "version": "8.0.7",
- "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-8.0.7.tgz",
- "integrity": "sha512-pkjE4mkBzQjdJT4/UmlKl3pX0rC9fZmjh7c6C9o7lv66Ac6w9WCnzPzhbPNxwZAzlF4mdq4CSWB5+FbK6FWCow==",
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-9.0.0.tgz",
+ "integrity": "sha512-tbPTid7d/p9jAA8CRZ3iomvrMaST0o6NYuY7v6JQZHpPRZ61mLFSPKYd7342NtOFuej9/+L48SOIxwfu2uDvtw==",
"license": "MIT-0",
"engines": {
"node": ">=6.0.0"
diff --git a/node_modules/brace-expansion/dist/commonjs/index.js b/node_modules/brace-expansion/dist/commonjs/index.js
index b9f3c6fd..33063dd3 100644
--- a/node_modules/brace-expansion/dist/commonjs/index.js
+++ b/node_modules/brace-expansion/dist/commonjs/index.js
@@ -155,7 +155,7 @@ function expand_(str, max, isTop) {
}
const pad = n.some(isPadded);
N = [];
- for (let i = x; test(i, y); i += incr) {
+ for (let i = x; test(i, y) && N.length < max; i += incr) {
let c;
if (isAlphaSequence) {
c = String.fromCharCode(i);
diff --git a/node_modules/brace-expansion/dist/commonjs/index.js.map b/node_modules/brace-expansion/dist/commonjs/index.js.map
index c9d15111..77dd0803 100644
--- a/node_modules/brace-expansion/dist/commonjs/index.js.map
+++ b/node_modules/brace-expansion/dist/commonjs/index.js.map
@@ -1 +1 @@
-{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { balanced } from 'balanced-match'\n\nconst escSlash = '\\0SLASH' + Math.random() + '\\0'\nconst escOpen = '\\0OPEN' + Math.random() + '\\0'\nconst escClose = '\\0CLOSE' + Math.random() + '\\0'\nconst escComma = '\\0COMMA' + Math.random() + '\\0'\nconst escPeriod = '\\0PERIOD' + Math.random() + '\\0'\nconst escSlashPattern = new RegExp(escSlash, 'g')\nconst escOpenPattern = new RegExp(escOpen, 'g')\nconst escClosePattern = new RegExp(escClose, 'g')\nconst escCommaPattern = new RegExp(escComma, 'g')\nconst escPeriodPattern = new RegExp(escPeriod, 'g')\nconst slashPattern = /\\\\\\\\/g\nconst openPattern = /\\\\{/g\nconst closePattern = /\\\\}/g\nconst commaPattern = /\\\\,/g\nconst periodPattern = /\\\\\\./g\n\nexport const EXPANSION_MAX = 100_000\n\nfunction numeric(str: string) {\n return !isNaN(str as any) ? parseInt(str, 10) : str.charCodeAt(0)\n}\n\nfunction escapeBraces(str: string) {\n return str\n .replace(slashPattern, escSlash)\n .replace(openPattern, escOpen)\n .replace(closePattern, escClose)\n .replace(commaPattern, escComma)\n .replace(periodPattern, escPeriod)\n}\n\nfunction unescapeBraces(str: string) {\n return str\n .replace(escSlashPattern, '\\\\')\n .replace(escOpenPattern, '{')\n .replace(escClosePattern, '}')\n .replace(escCommaPattern, ',')\n .replace(escPeriodPattern, '.')\n}\n\n/**\n * Basically just str.split(\",\"), but handling cases\n * where we have nested braced sections, which should be\n * treated as individual members, like {a,{b,c},d}\n */\nfunction parseCommaParts(str: string) {\n if (!str) {\n return ['']\n }\n\n const parts: string[] = []\n const m = balanced('{', '}', str)\n\n if (!m) {\n return str.split(',')\n }\n\n const { pre, body, post } = m\n const p = pre.split(',')\n\n p[p.length - 1] += '{' + body + '}'\n const postParts = parseCommaParts(post)\n if (post.length) {\n ;(p[p.length - 1] as string) += postParts.shift()\n p.push.apply(p, postParts)\n }\n\n parts.push.apply(parts, p)\n\n return parts\n}\n\nexport type BraceExpansionOptions = {\n max?: number\n}\n\nexport function expand(str: string, options: BraceExpansionOptions = {}) {\n if (!str) {\n return []\n }\n\n const { max = EXPANSION_MAX } = options\n\n // I don't know why Bash 4.3 does this, but it does.\n // Anything starting with {} will have the first two bytes preserved\n // but *only* at the top level, so {},a}b will not expand to anything,\n // but a{},b}c will be expanded to [a}c,abc].\n // One could argue that this is a bug in Bash, but since the goal of\n // this module is to match Bash's rules, we escape a leading {}\n if (str.slice(0, 2) === '{}') {\n str = '\\\\{\\\\}' + str.slice(2)\n }\n\n return expand_(escapeBraces(str), max, true).map(unescapeBraces)\n}\n\nfunction embrace(str: string) {\n return '{' + str + '}'\n}\n\nfunction isPadded(el: string) {\n return /^-?0\\d/.test(el)\n}\n\nfunction lte(i: number, y: number) {\n return i <= y\n}\n\nfunction gte(i: number, y: number) {\n return i >= y\n}\n\nfunction expand_(str: string, max: number, isTop: boolean): string[] {\n /** @type {string[]} */\n const expansions: string[] = []\n\n const m = balanced('{', '}', str)\n if (!m) return [str]\n\n // no need to expand pre, since it is guaranteed to be free of brace-sets\n const pre = m.pre\n const post: string[] = m.post.length ? expand_(m.post, max, false) : ['']\n\n if (/\\$$/.test(m.pre)) {\n for (let k = 0; k < post.length && k < max; k++) {\n const expansion = pre + '{' + m.body + '}' + post[k]\n expansions.push(expansion)\n }\n } else {\n const isNumericSequence = /^-?\\d+\\.\\.-?\\d+(?:\\.\\.-?\\d+)?$/.test(m.body)\n const isAlphaSequence = /^[a-zA-Z]\\.\\.[a-zA-Z](?:\\.\\.-?\\d+)?$/.test(\n m.body,\n )\n const isSequence = isNumericSequence || isAlphaSequence\n const isOptions = m.body.indexOf(',') >= 0\n if (!isSequence && !isOptions) {\n // {a},b}\n if (m.post.match(/,(?!,).*\\}/)) {\n str = m.pre + '{' + m.body + escClose + m.post\n return expand_(str, max, true)\n }\n return [str]\n }\n\n let n: string[]\n if (isSequence) {\n n = m.body.split(/\\.\\./)\n } else {\n n = parseCommaParts(m.body)\n if (n.length === 1 && n[0] !== undefined) {\n // x{{a,b}}y ==> x{a}y x{b}y\n n = expand_(n[0], max, false).map(embrace)\n //XXX is this necessary? Can't seem to hit it in tests.\n /* c8 ignore start */\n if (n.length === 1) {\n return post.map(p => m.pre + n[0] + p)\n }\n /* c8 ignore stop */\n }\n }\n\n // at this point, n is the parts, and we know it's not a comma set\n // with a single entry.\n let N: string[]\n\n if (isSequence && n[0] !== undefined && n[1] !== undefined) {\n const x = numeric(n[0])\n const y = numeric(n[1])\n const width = Math.max(n[0].length, n[1].length)\n let incr =\n n.length === 3 && n[2] !== undefined ?\n Math.max(Math.abs(numeric(n[2])), 1)\n : 1\n let test = lte\n const reverse = y < x\n if (reverse) {\n incr *= -1\n test = gte\n }\n const pad = n.some(isPadded)\n\n N = []\n\n for (let i = x; test(i, y); i += incr) {\n let c\n if (isAlphaSequence) {\n c = String.fromCharCode(i)\n if (c === '\\\\') {\n c = ''\n }\n } else {\n c = String(i)\n if (pad) {\n const need = width - c.length\n if (need > 0) {\n const z = new Array(need + 1).join('0')\n if (i < 0) {\n c = '-' + z + c.slice(1)\n } else {\n c = z + c\n }\n }\n }\n }\n N.push(c)\n }\n } else {\n N = []\n\n for (let j = 0; j < n.length; j++) {\n N.push.apply(N, expand_(n[j] as string, max, false))\n }\n }\n\n for (let j = 0; j < N.length; j++) {\n for (let k = 0; k < post.length && expansions.length < max; k++) {\n const expansion = pre + N[j] + post[k]\n if (!isTop || isSequence || expansion) {\n expansions.push(expansion)\n }\n }\n }\n }\n\n return expansions\n}\n"]}
\ No newline at end of file
+{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { balanced } from 'balanced-match'\n\nconst escSlash = '\\0SLASH' + Math.random() + '\\0'\nconst escOpen = '\\0OPEN' + Math.random() + '\\0'\nconst escClose = '\\0CLOSE' + Math.random() + '\\0'\nconst escComma = '\\0COMMA' + Math.random() + '\\0'\nconst escPeriod = '\\0PERIOD' + Math.random() + '\\0'\nconst escSlashPattern = new RegExp(escSlash, 'g')\nconst escOpenPattern = new RegExp(escOpen, 'g')\nconst escClosePattern = new RegExp(escClose, 'g')\nconst escCommaPattern = new RegExp(escComma, 'g')\nconst escPeriodPattern = new RegExp(escPeriod, 'g')\nconst slashPattern = /\\\\\\\\/g\nconst openPattern = /\\\\{/g\nconst closePattern = /\\\\}/g\nconst commaPattern = /\\\\,/g\nconst periodPattern = /\\\\\\./g\n\nexport const EXPANSION_MAX = 100_000\n\nfunction numeric(str: string) {\n return !isNaN(str as any) ? parseInt(str, 10) : str.charCodeAt(0)\n}\n\nfunction escapeBraces(str: string) {\n return str\n .replace(slashPattern, escSlash)\n .replace(openPattern, escOpen)\n .replace(closePattern, escClose)\n .replace(commaPattern, escComma)\n .replace(periodPattern, escPeriod)\n}\n\nfunction unescapeBraces(str: string) {\n return str\n .replace(escSlashPattern, '\\\\')\n .replace(escOpenPattern, '{')\n .replace(escClosePattern, '}')\n .replace(escCommaPattern, ',')\n .replace(escPeriodPattern, '.')\n}\n\n/**\n * Basically just str.split(\",\"), but handling cases\n * where we have nested braced sections, which should be\n * treated as individual members, like {a,{b,c},d}\n */\nfunction parseCommaParts(str: string) {\n if (!str) {\n return ['']\n }\n\n const parts: string[] = []\n const m = balanced('{', '}', str)\n\n if (!m) {\n return str.split(',')\n }\n\n const { pre, body, post } = m\n const p = pre.split(',')\n\n p[p.length - 1] += '{' + body + '}'\n const postParts = parseCommaParts(post)\n if (post.length) {\n ;(p[p.length - 1] as string) += postParts.shift()\n p.push.apply(p, postParts)\n }\n\n parts.push.apply(parts, p)\n\n return parts\n}\n\nexport type BraceExpansionOptions = {\n max?: number\n}\n\nexport function expand(str: string, options: BraceExpansionOptions = {}) {\n if (!str) {\n return []\n }\n\n const { max = EXPANSION_MAX } = options\n\n // I don't know why Bash 4.3 does this, but it does.\n // Anything starting with {} will have the first two bytes preserved\n // but *only* at the top level, so {},a}b will not expand to anything,\n // but a{},b}c will be expanded to [a}c,abc].\n // One could argue that this is a bug in Bash, but since the goal of\n // this module is to match Bash's rules, we escape a leading {}\n if (str.slice(0, 2) === '{}') {\n str = '\\\\{\\\\}' + str.slice(2)\n }\n\n return expand_(escapeBraces(str), max, true).map(unescapeBraces)\n}\n\nfunction embrace(str: string) {\n return '{' + str + '}'\n}\n\nfunction isPadded(el: string) {\n return /^-?0\\d/.test(el)\n}\n\nfunction lte(i: number, y: number) {\n return i <= y\n}\n\nfunction gte(i: number, y: number) {\n return i >= y\n}\n\nfunction expand_(str: string, max: number, isTop: boolean): string[] {\n /** @type {string[]} */\n const expansions: string[] = []\n\n const m = balanced('{', '}', str)\n if (!m) return [str]\n\n // no need to expand pre, since it is guaranteed to be free of brace-sets\n const pre = m.pre\n const post: string[] = m.post.length ? expand_(m.post, max, false) : ['']\n\n if (/\\$$/.test(m.pre)) {\n for (let k = 0; k < post.length && k < max; k++) {\n const expansion = pre + '{' + m.body + '}' + post[k]\n expansions.push(expansion)\n }\n } else {\n const isNumericSequence = /^-?\\d+\\.\\.-?\\d+(?:\\.\\.-?\\d+)?$/.test(m.body)\n const isAlphaSequence = /^[a-zA-Z]\\.\\.[a-zA-Z](?:\\.\\.-?\\d+)?$/.test(\n m.body,\n )\n const isSequence = isNumericSequence || isAlphaSequence\n const isOptions = m.body.indexOf(',') >= 0\n if (!isSequence && !isOptions) {\n // {a},b}\n if (m.post.match(/,(?!,).*\\}/)) {\n str = m.pre + '{' + m.body + escClose + m.post\n return expand_(str, max, true)\n }\n return [str]\n }\n\n let n: string[]\n if (isSequence) {\n n = m.body.split(/\\.\\./)\n } else {\n n = parseCommaParts(m.body)\n if (n.length === 1 && n[0] !== undefined) {\n // x{{a,b}}y ==> x{a}y x{b}y\n n = expand_(n[0], max, false).map(embrace)\n //XXX is this necessary? Can't seem to hit it in tests.\n /* c8 ignore start */\n if (n.length === 1) {\n return post.map(p => m.pre + n[0] + p)\n }\n /* c8 ignore stop */\n }\n }\n\n // at this point, n is the parts, and we know it's not a comma set\n // with a single entry.\n let N: string[]\n\n if (isSequence && n[0] !== undefined && n[1] !== undefined) {\n const x = numeric(n[0])\n const y = numeric(n[1])\n const width = Math.max(n[0].length, n[1].length)\n let incr =\n n.length === 3 && n[2] !== undefined ?\n Math.max(Math.abs(numeric(n[2])), 1)\n : 1\n let test = lte\n const reverse = y < x\n if (reverse) {\n incr *= -1\n test = gte\n }\n const pad = n.some(isPadded)\n\n N = []\n\n for (let i = x; test(i, y) && N.length < max; i += incr) {\n let c\n if (isAlphaSequence) {\n c = String.fromCharCode(i)\n if (c === '\\\\') {\n c = ''\n }\n } else {\n c = String(i)\n if (pad) {\n const need = width - c.length\n if (need > 0) {\n const z = new Array(need + 1).join('0')\n if (i < 0) {\n c = '-' + z + c.slice(1)\n } else {\n c = z + c\n }\n }\n }\n }\n N.push(c)\n }\n } else {\n N = []\n\n for (let j = 0; j < n.length; j++) {\n N.push.apply(N, expand_(n[j] as string, max, false))\n }\n }\n\n for (let j = 0; j < N.length; j++) {\n for (let k = 0; k < post.length && expansions.length < max; k++) {\n const expansion = pre + N[j] + post[k]\n if (!isTop || isSequence || expansion) {\n expansions.push(expansion)\n }\n }\n }\n }\n\n return expansions\n}\n"]}
\ No newline at end of file
diff --git a/node_modules/brace-expansion/dist/esm/index.js b/node_modules/brace-expansion/dist/esm/index.js
index 855e22cd..32399e7b 100644
--- a/node_modules/brace-expansion/dist/esm/index.js
+++ b/node_modules/brace-expansion/dist/esm/index.js
@@ -151,7 +151,7 @@ function expand_(str, max, isTop) {
}
const pad = n.some(isPadded);
N = [];
- for (let i = x; test(i, y); i += incr) {
+ for (let i = x; test(i, y) && N.length < max; i += incr) {
let c;
if (isAlphaSequence) {
c = String.fromCharCode(i);
diff --git a/node_modules/brace-expansion/dist/esm/index.js.map b/node_modules/brace-expansion/dist/esm/index.js.map
index 1bf0ab5b..63a6a2a9 100644
--- a/node_modules/brace-expansion/dist/esm/index.js.map
+++ b/node_modules/brace-expansion/dist/esm/index.js.map
@@ -1 +1 @@
-{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { balanced } from 'balanced-match'\n\nconst escSlash = '\\0SLASH' + Math.random() + '\\0'\nconst escOpen = '\\0OPEN' + Math.random() + '\\0'\nconst escClose = '\\0CLOSE' + Math.random() + '\\0'\nconst escComma = '\\0COMMA' + Math.random() + '\\0'\nconst escPeriod = '\\0PERIOD' + Math.random() + '\\0'\nconst escSlashPattern = new RegExp(escSlash, 'g')\nconst escOpenPattern = new RegExp(escOpen, 'g')\nconst escClosePattern = new RegExp(escClose, 'g')\nconst escCommaPattern = new RegExp(escComma, 'g')\nconst escPeriodPattern = new RegExp(escPeriod, 'g')\nconst slashPattern = /\\\\\\\\/g\nconst openPattern = /\\\\{/g\nconst closePattern = /\\\\}/g\nconst commaPattern = /\\\\,/g\nconst periodPattern = /\\\\\\./g\n\nexport const EXPANSION_MAX = 100_000\n\nfunction numeric(str: string) {\n return !isNaN(str as any) ? parseInt(str, 10) : str.charCodeAt(0)\n}\n\nfunction escapeBraces(str: string) {\n return str\n .replace(slashPattern, escSlash)\n .replace(openPattern, escOpen)\n .replace(closePattern, escClose)\n .replace(commaPattern, escComma)\n .replace(periodPattern, escPeriod)\n}\n\nfunction unescapeBraces(str: string) {\n return str\n .replace(escSlashPattern, '\\\\')\n .replace(escOpenPattern, '{')\n .replace(escClosePattern, '}')\n .replace(escCommaPattern, ',')\n .replace(escPeriodPattern, '.')\n}\n\n/**\n * Basically just str.split(\",\"), but handling cases\n * where we have nested braced sections, which should be\n * treated as individual members, like {a,{b,c},d}\n */\nfunction parseCommaParts(str: string) {\n if (!str) {\n return ['']\n }\n\n const parts: string[] = []\n const m = balanced('{', '}', str)\n\n if (!m) {\n return str.split(',')\n }\n\n const { pre, body, post } = m\n const p = pre.split(',')\n\n p[p.length - 1] += '{' + body + '}'\n const postParts = parseCommaParts(post)\n if (post.length) {\n ;(p[p.length - 1] as string) += postParts.shift()\n p.push.apply(p, postParts)\n }\n\n parts.push.apply(parts, p)\n\n return parts\n}\n\nexport type BraceExpansionOptions = {\n max?: number\n}\n\nexport function expand(str: string, options: BraceExpansionOptions = {}) {\n if (!str) {\n return []\n }\n\n const { max = EXPANSION_MAX } = options\n\n // I don't know why Bash 4.3 does this, but it does.\n // Anything starting with {} will have the first two bytes preserved\n // but *only* at the top level, so {},a}b will not expand to anything,\n // but a{},b}c will be expanded to [a}c,abc].\n // One could argue that this is a bug in Bash, but since the goal of\n // this module is to match Bash's rules, we escape a leading {}\n if (str.slice(0, 2) === '{}') {\n str = '\\\\{\\\\}' + str.slice(2)\n }\n\n return expand_(escapeBraces(str), max, true).map(unescapeBraces)\n}\n\nfunction embrace(str: string) {\n return '{' + str + '}'\n}\n\nfunction isPadded(el: string) {\n return /^-?0\\d/.test(el)\n}\n\nfunction lte(i: number, y: number) {\n return i <= y\n}\n\nfunction gte(i: number, y: number) {\n return i >= y\n}\n\nfunction expand_(str: string, max: number, isTop: boolean): string[] {\n /** @type {string[]} */\n const expansions: string[] = []\n\n const m = balanced('{', '}', str)\n if (!m) return [str]\n\n // no need to expand pre, since it is guaranteed to be free of brace-sets\n const pre = m.pre\n const post: string[] = m.post.length ? expand_(m.post, max, false) : ['']\n\n if (/\\$$/.test(m.pre)) {\n for (let k = 0; k < post.length && k < max; k++) {\n const expansion = pre + '{' + m.body + '}' + post[k]\n expansions.push(expansion)\n }\n } else {\n const isNumericSequence = /^-?\\d+\\.\\.-?\\d+(?:\\.\\.-?\\d+)?$/.test(m.body)\n const isAlphaSequence = /^[a-zA-Z]\\.\\.[a-zA-Z](?:\\.\\.-?\\d+)?$/.test(\n m.body,\n )\n const isSequence = isNumericSequence || isAlphaSequence\n const isOptions = m.body.indexOf(',') >= 0\n if (!isSequence && !isOptions) {\n // {a},b}\n if (m.post.match(/,(?!,).*\\}/)) {\n str = m.pre + '{' + m.body + escClose + m.post\n return expand_(str, max, true)\n }\n return [str]\n }\n\n let n: string[]\n if (isSequence) {\n n = m.body.split(/\\.\\./)\n } else {\n n = parseCommaParts(m.body)\n if (n.length === 1 && n[0] !== undefined) {\n // x{{a,b}}y ==> x{a}y x{b}y\n n = expand_(n[0], max, false).map(embrace)\n //XXX is this necessary? Can't seem to hit it in tests.\n /* c8 ignore start */\n if (n.length === 1) {\n return post.map(p => m.pre + n[0] + p)\n }\n /* c8 ignore stop */\n }\n }\n\n // at this point, n is the parts, and we know it's not a comma set\n // with a single entry.\n let N: string[]\n\n if (isSequence && n[0] !== undefined && n[1] !== undefined) {\n const x = numeric(n[0])\n const y = numeric(n[1])\n const width = Math.max(n[0].length, n[1].length)\n let incr =\n n.length === 3 && n[2] !== undefined ?\n Math.max(Math.abs(numeric(n[2])), 1)\n : 1\n let test = lte\n const reverse = y < x\n if (reverse) {\n incr *= -1\n test = gte\n }\n const pad = n.some(isPadded)\n\n N = []\n\n for (let i = x; test(i, y); i += incr) {\n let c\n if (isAlphaSequence) {\n c = String.fromCharCode(i)\n if (c === '\\\\') {\n c = ''\n }\n } else {\n c = String(i)\n if (pad) {\n const need = width - c.length\n if (need > 0) {\n const z = new Array(need + 1).join('0')\n if (i < 0) {\n c = '-' + z + c.slice(1)\n } else {\n c = z + c\n }\n }\n }\n }\n N.push(c)\n }\n } else {\n N = []\n\n for (let j = 0; j < n.length; j++) {\n N.push.apply(N, expand_(n[j] as string, max, false))\n }\n }\n\n for (let j = 0; j < N.length; j++) {\n for (let k = 0; k < post.length && expansions.length < max; k++) {\n const expansion = pre + N[j] + post[k]\n if (!isTop || isSequence || expansion) {\n expansions.push(expansion)\n }\n }\n }\n }\n\n return expansions\n}\n"]}
\ No newline at end of file
+{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { balanced } from 'balanced-match'\n\nconst escSlash = '\\0SLASH' + Math.random() + '\\0'\nconst escOpen = '\\0OPEN' + Math.random() + '\\0'\nconst escClose = '\\0CLOSE' + Math.random() + '\\0'\nconst escComma = '\\0COMMA' + Math.random() + '\\0'\nconst escPeriod = '\\0PERIOD' + Math.random() + '\\0'\nconst escSlashPattern = new RegExp(escSlash, 'g')\nconst escOpenPattern = new RegExp(escOpen, 'g')\nconst escClosePattern = new RegExp(escClose, 'g')\nconst escCommaPattern = new RegExp(escComma, 'g')\nconst escPeriodPattern = new RegExp(escPeriod, 'g')\nconst slashPattern = /\\\\\\\\/g\nconst openPattern = /\\\\{/g\nconst closePattern = /\\\\}/g\nconst commaPattern = /\\\\,/g\nconst periodPattern = /\\\\\\./g\n\nexport const EXPANSION_MAX = 100_000\n\nfunction numeric(str: string) {\n return !isNaN(str as any) ? parseInt(str, 10) : str.charCodeAt(0)\n}\n\nfunction escapeBraces(str: string) {\n return str\n .replace(slashPattern, escSlash)\n .replace(openPattern, escOpen)\n .replace(closePattern, escClose)\n .replace(commaPattern, escComma)\n .replace(periodPattern, escPeriod)\n}\n\nfunction unescapeBraces(str: string) {\n return str\n .replace(escSlashPattern, '\\\\')\n .replace(escOpenPattern, '{')\n .replace(escClosePattern, '}')\n .replace(escCommaPattern, ',')\n .replace(escPeriodPattern, '.')\n}\n\n/**\n * Basically just str.split(\",\"), but handling cases\n * where we have nested braced sections, which should be\n * treated as individual members, like {a,{b,c},d}\n */\nfunction parseCommaParts(str: string) {\n if (!str) {\n return ['']\n }\n\n const parts: string[] = []\n const m = balanced('{', '}', str)\n\n if (!m) {\n return str.split(',')\n }\n\n const { pre, body, post } = m\n const p = pre.split(',')\n\n p[p.length - 1] += '{' + body + '}'\n const postParts = parseCommaParts(post)\n if (post.length) {\n ;(p[p.length - 1] as string) += postParts.shift()\n p.push.apply(p, postParts)\n }\n\n parts.push.apply(parts, p)\n\n return parts\n}\n\nexport type BraceExpansionOptions = {\n max?: number\n}\n\nexport function expand(str: string, options: BraceExpansionOptions = {}) {\n if (!str) {\n return []\n }\n\n const { max = EXPANSION_MAX } = options\n\n // I don't know why Bash 4.3 does this, but it does.\n // Anything starting with {} will have the first two bytes preserved\n // but *only* at the top level, so {},a}b will not expand to anything,\n // but a{},b}c will be expanded to [a}c,abc].\n // One could argue that this is a bug in Bash, but since the goal of\n // this module is to match Bash's rules, we escape a leading {}\n if (str.slice(0, 2) === '{}') {\n str = '\\\\{\\\\}' + str.slice(2)\n }\n\n return expand_(escapeBraces(str), max, true).map(unescapeBraces)\n}\n\nfunction embrace(str: string) {\n return '{' + str + '}'\n}\n\nfunction isPadded(el: string) {\n return /^-?0\\d/.test(el)\n}\n\nfunction lte(i: number, y: number) {\n return i <= y\n}\n\nfunction gte(i: number, y: number) {\n return i >= y\n}\n\nfunction expand_(str: string, max: number, isTop: boolean): string[] {\n /** @type {string[]} */\n const expansions: string[] = []\n\n const m = balanced('{', '}', str)\n if (!m) return [str]\n\n // no need to expand pre, since it is guaranteed to be free of brace-sets\n const pre = m.pre\n const post: string[] = m.post.length ? expand_(m.post, max, false) : ['']\n\n if (/\\$$/.test(m.pre)) {\n for (let k = 0; k < post.length && k < max; k++) {\n const expansion = pre + '{' + m.body + '}' + post[k]\n expansions.push(expansion)\n }\n } else {\n const isNumericSequence = /^-?\\d+\\.\\.-?\\d+(?:\\.\\.-?\\d+)?$/.test(m.body)\n const isAlphaSequence = /^[a-zA-Z]\\.\\.[a-zA-Z](?:\\.\\.-?\\d+)?$/.test(\n m.body,\n )\n const isSequence = isNumericSequence || isAlphaSequence\n const isOptions = m.body.indexOf(',') >= 0\n if (!isSequence && !isOptions) {\n // {a},b}\n if (m.post.match(/,(?!,).*\\}/)) {\n str = m.pre + '{' + m.body + escClose + m.post\n return expand_(str, max, true)\n }\n return [str]\n }\n\n let n: string[]\n if (isSequence) {\n n = m.body.split(/\\.\\./)\n } else {\n n = parseCommaParts(m.body)\n if (n.length === 1 && n[0] !== undefined) {\n // x{{a,b}}y ==> x{a}y x{b}y\n n = expand_(n[0], max, false).map(embrace)\n //XXX is this necessary? Can't seem to hit it in tests.\n /* c8 ignore start */\n if (n.length === 1) {\n return post.map(p => m.pre + n[0] + p)\n }\n /* c8 ignore stop */\n }\n }\n\n // at this point, n is the parts, and we know it's not a comma set\n // with a single entry.\n let N: string[]\n\n if (isSequence && n[0] !== undefined && n[1] !== undefined) {\n const x = numeric(n[0])\n const y = numeric(n[1])\n const width = Math.max(n[0].length, n[1].length)\n let incr =\n n.length === 3 && n[2] !== undefined ?\n Math.max(Math.abs(numeric(n[2])), 1)\n : 1\n let test = lte\n const reverse = y < x\n if (reverse) {\n incr *= -1\n test = gte\n }\n const pad = n.some(isPadded)\n\n N = []\n\n for (let i = x; test(i, y) && N.length < max; i += incr) {\n let c\n if (isAlphaSequence) {\n c = String.fromCharCode(i)\n if (c === '\\\\') {\n c = ''\n }\n } else {\n c = String(i)\n if (pad) {\n const need = width - c.length\n if (need > 0) {\n const z = new Array(need + 1).join('0')\n if (i < 0) {\n c = '-' + z + c.slice(1)\n } else {\n c = z + c\n }\n }\n }\n }\n N.push(c)\n }\n } else {\n N = []\n\n for (let j = 0; j < n.length; j++) {\n N.push.apply(N, expand_(n[j] as string, max, false))\n }\n }\n\n for (let j = 0; j < N.length; j++) {\n for (let k = 0; k < post.length && expansions.length < max; k++) {\n const expansion = pre + N[j] + post[k]\n if (!isTop || isSequence || expansion) {\n expansions.push(expansion)\n }\n }\n }\n }\n\n return expansions\n}\n"]}
\ No newline at end of file
diff --git a/node_modules/brace-expansion/package.json b/node_modules/brace-expansion/package.json
index 83a82896..81524809 100644
--- a/node_modules/brace-expansion/package.json
+++ b/node_modules/brace-expansion/package.json
@@ -1,7 +1,7 @@
{
"name": "brace-expansion",
"description": "Brace expansion as known from sh/bash",
- "version": "5.0.5",
+ "version": "5.0.6",
"files": [
"dist"
],
diff --git a/node_modules/nodemailer/CHANGELOG.md b/node_modules/nodemailer/CHANGELOG.md
index d8ebaed8..e47bfd64 100644
--- a/node_modules/nodemailer/CHANGELOG.md
+++ b/node_modules/nodemailer/CHANGELOG.md
@@ -1,5 +1,52 @@
# CHANGELOG
+## [9.0.0](https://github.com/nodemailer/nodemailer/compare/v8.0.11...v9.0.0) (2026-06-14)
+
+
+### ⚠ BREAKING CHANGES
+
+* HTTPS requests made while fetching remote content (attachment href/path URLs, OAuth2 token endpoints, HTTP/HTTPS proxy CONNECT) now validate the server's TLS certificate by default. Requests to hosts with self-signed, expired, or hostname-mismatched certificates that previously succeeded will now fail. Opt back out per request with tls.rejectUnauthorized=false (transport options, or a per-attachment `tls` option).
+
+### Bug Fixes
+
+* replace deprecated url.parse with a WHATWG URL wrapper ([0c080fb](https://github.com/nodemailer/nodemailer/commit/0c080fbf3278926f013a5c2ad06f5f6f0e18f5ed))
+* validate TLS certificates by default when fetching remote content ([6a947ac](https://github.com/nodemailer/nodemailer/commit/6a947ac7114a16da1e6a50d9a6f4e17026ce145d))
+
+## [8.0.11](https://github.com/nodemailer/nodemailer/compare/v8.0.10...v8.0.11) (2026-06-10)
+
+
+### Bug Fixes
+
+* apply the transport-level newline option in stream and sendmail transports ([cb4f904](https://github.com/nodemailer/nodemailer/commit/cb4f904a53d2c2feeaf327203c92378d46304398))
+* include icalEvent path/href content in the application/ics attachment ([b801c48](https://github.com/nodemailer/nodemailer/commit/b801c48fab8e9b71bc7e0ea1fb32ce6b34675b15))
+* parse Ethereal response props without polynomial regex backtracking ([067aebe](https://github.com/nodemailer/nodemailer/commit/067aebec83b8cbe7682905e89b30ab19d260b503))
+* resolve oauth2_provision_cb at send time for non-pooled SMTP transports ([203c8ec](https://github.com/nodemailer/nodemailer/commit/203c8ecf97594ac2e69919b0f3ba966c0f86750e))
+* return the promise from every resolveContent branch ([07ffe8c](https://github.com/nodemailer/nodemailer/commit/07ffe8cfd97f0486b8c7b541f398922ddab47882))
+* strip the url scheme from List-ID header values ([77e5885](https://github.com/nodemailer/nodemailer/commit/77e5885cfa0c6723ea7749c1ee74b1c11aeb78bd))
+* tag AWS SES transport errors with the ESES code ([efa647a](https://github.com/nodemailer/nodemailer/commit/efa647a125dd698413a7cf6813b8e36881a06f91))
+
+## [8.0.10](https://github.com/nodemailer/nodemailer/compare/v8.0.9...v8.0.10) (2026-05-29)
+
+
+### Bug Fixes
+
+* fall back to lower-severity handler when custom logger lacks a level method ([6d849df](https://github.com/nodemailer/nodemailer/commit/6d849df59a56184b48844ed10b5fb7b8e9f74634))
+
+## [8.0.9](https://github.com/nodemailer/nodemailer/compare/v8.0.8...v8.0.9) (2026-05-26)
+
+
+### Bug Fixes
+
+* two pending security advisories (jsonTransport access bypass, List-* CRLF injection) ([#1820](https://github.com/nodemailer/nodemailer/issues/1820)) ([5f69497](https://github.com/nodemailer/nodemailer/commit/5f694977da2e0e13dc947037566e8e689a01217e))
+
+## [8.0.8](https://github.com/nodemailer/nodemailer/compare/v8.0.7...v8.0.8) (2026-05-23)
+
+
+### Bug Fixes
+
+* enforce strict TLS for OAuth2 and Ethereal credential requests ([#1818](https://github.com/nodemailer/nodemailer/issues/1818)) ([833d6e5](https://github.com/nodemailer/nodemailer/commit/833d6e58c8b717962bbb1b23e16923cd267c3bc9))
+* four listener/stream leaks in SMTP transport, connection, pool ([#1817](https://github.com/nodemailer/nodemailer/issues/1817)) ([850bb91](https://github.com/nodemailer/nodemailer/commit/850bb91bff7707ed498c1424df01c4e5b30ea14b))
+
## [8.0.7](https://github.com/nodemailer/nodemailer/compare/v8.0.6...v8.0.7) (2026-04-27)
diff --git a/node_modules/nodemailer/CLAUDE.md b/node_modules/nodemailer/CLAUDE.md
index e31b392c..c0f6d6cd 100644
--- a/node_modules/nodemailer/CLAUDE.md
+++ b/node_modules/nodemailer/CLAUDE.md
@@ -50,6 +50,7 @@ Conventional Commit prefixes used in this repo: `fix:`, `feat:`, `chore:`, `docs
## Security
This is a widely-deployed library — security-sensitive changes get extra scrutiny:
+
- SMTP command injection: any user-controllable value that flows into a written SMTP command (envelope addresses, sizes, the `name`/EHLO option, headers) must be CRLF-stripped or rejected at the boundary. Sanitize at the assignment, not at every call site.
- Server reply parsing in `lib/smtp-connection/index.js` uses a `'binary'` byte-container intermediate to reassemble multi-byte UTF-8 across socket chunks; the actual decode happens at line boundaries via `decodeServerResponse`. Don't change the chunk-buffering encoding without understanding why.
- Reference the GHSA ID in commit messages for advisories.
diff --git a/node_modules/nodemailer/SECURITY.md b/node_modules/nodemailer/SECURITY.md
new file mode 100644
index 00000000..2243c06f
--- /dev/null
+++ b/node_modules/nodemailer/SECURITY.md
@@ -0,0 +1,65 @@
+# Security Policy
+
+Nodemailer is a widely deployed, zero-dependency e-mail library. We take security
+reports seriously and aim to respond quickly.
+
+## Supported Versions
+
+Security fixes are released only against the latest major version. We do not
+backport patches to older majors — upgrading to the current release line is the
+supported way to receive security updates.
+
+| Version | Supported |
+| ------- | ------------------ |
+| 8.x | :white_check_mark: |
+| < 8.0 | :x: |
+
+If you are on an older major, please upgrade. See the migration notes at
+ before updating.
+
+## Reporting a Vulnerability
+
+**Please do not report security vulnerabilities through public GitHub issues,
+pull requests, or discussions.**
+
+Report privately through one of the following channels:
+
+1. **GitHub Security Advisories (preferred).** Open a private report at
+ . This keeps
+ the discussion private until a fix is published and lets us credit you.
+2. **Email.** Send details to **andris@reinman.eu** (the contact listed in
+ [`SECURITY.txt`](SECURITY.txt)). Encrypt sensitive details if possible.
+
+When reporting, please include as much of the following as you can:
+
+- The affected version(s) and environment (Node.js version, OS).
+- The component involved (e.g. SMTP connection, address parsing, MIME/header
+ generation, DKIM).
+- A clear description of the issue and its impact (e.g. header/SMTP command
+ injection, information disclosure, DoS).
+- A minimal proof of concept or reproduction steps.
+- Any suggested remediation, if you have one.
+
+Nodemailer is maintained by a single person, so there is no guaranteed response
+time — sometimes reports are handled within hours, sometimes they take longer.
+Accepted issues are fixed in a new release and coordinated through a GitHub
+Security Advisory, and reporters who wish to be named are credited.
+
+## CVEs
+
+We track and disclose vulnerabilities through GitHub Security Advisories. We do
+not request or manage CVE identifiers ourselves. If you need a CVE assigned for a
+reported issue, please request one yourself — for example, through GitHub's own
+CVE request flow on the published advisory, or another CNA.
+
+## Scope
+
+In scope: the `nodemailer` package source in this repository — message and MIME
+generation, SMTP/LMTP client behaviour, address parsing, header handling, DKIM
+signing, and the bundled transports.
+
+Out of scope: vulnerabilities in your own application code, misconfiguration of
+your mail server or credentials, social-engineering reports, and issues in
+third-party services Nodemailer connects to.
+
+Thank you for helping keep Nodemailer and its users safe.
diff --git a/node_modules/nodemailer/lib/fetch/cookies.js b/node_modules/nodemailer/lib/fetch/cookies.js
index bd1c328e..2b5e452a 100644
--- a/node_modules/nodemailer/lib/fetch/cookies.js
+++ b/node_modules/nodemailer/lib/fetch/cookies.js
@@ -2,7 +2,7 @@
// module to handle cookies
-const urllib = require('url');
+const urllib = require('../shared/url');
const SESSION_TIMEOUT = 1800; // 30 min
diff --git a/node_modules/nodemailer/lib/fetch/index.js b/node_modules/nodemailer/lib/fetch/index.js
index 6c838365..9cf4d2fd 100644
--- a/node_modules/nodemailer/lib/fetch/index.js
+++ b/node_modules/nodemailer/lib/fetch/index.js
@@ -2,7 +2,7 @@
const http = require('http');
const https = require('https');
-const urllib = require('url');
+const urllib = require('../shared/url');
const zlib = require('zlib');
const { PassThrough } = require('stream');
const Cookies = require('./cookies');
@@ -123,7 +123,10 @@ function nmfetch(url, options) {
path: parsed.path,
port: parsed.port ? parsed.port : parsed.protocol === 'https:' ? 443 : 80,
headers,
- rejectUnauthorized: false,
+ // Validate TLS certificates by default. Callers that genuinely need to
+ // reach a self-signed/internal host opt out explicitly with
+ // options.tls = { rejectUnauthorized: false }.
+ rejectUnauthorized: true,
agent: false
};
@@ -212,7 +215,27 @@ function nmfetch(url, options) {
// redirect does not include POST body
options.method = 'GET';
options.body = false;
- return nmfetch(urllib.resolve(url, res.headers.location), options);
+
+ const redirectUrl = urllib.resolve(url, res.headers.location);
+ const redirectParsed = urllib.parse(redirectUrl);
+
+ // Do not forward credentials when the redirect leaves the original
+ // security context: a different host, or a downgrade from https to
+ // http (which would otherwise put them on the wire in cleartext).
+ // Strip sensitive request headers so an attacker who controls the
+ // redirect target cannot harvest them.
+ const crossHost = redirectParsed.hostname !== parsed.hostname;
+ const downgrade = parsed.protocol === 'https:' && redirectParsed.protocol === 'http:';
+ if (options.headers && (crossHost || downgrade)) {
+ const sensitive = ['authorization', 'cookie', 'proxy-authorization'];
+ Object.keys(options.headers).forEach(key => {
+ if (sensitive.includes(key.toLowerCase())) {
+ delete options.headers[key];
+ }
+ });
+ }
+
+ return nmfetch(redirectUrl, options);
}
fetchRes.statusCode = res.statusCode;
diff --git a/node_modules/nodemailer/lib/mail-composer/index.js b/node_modules/nodemailer/lib/mail-composer/index.js
index ccc93699..007c7e5a 100644
--- a/node_modules/nodemailer/lib/mail-composer/index.js
+++ b/node_modules/nodemailer/lib/mail-composer/index.js
@@ -83,7 +83,7 @@ class MailComposer {
* @returns {Object} An object of arrays (`related` and `attached`)
*/
getAttachments(findRelated) {
- let icalEvent, eventObject;
+ let eventObject;
const attachments = [].concat(this.mail.attachments || []).map((attachment, i) => {
if (/^data:/i.test(attachment.path || attachment.href)) {
attachment = this._processDataUrl(attachment);
@@ -142,7 +142,8 @@ class MailComposer {
} else if (attachment.href) {
data.content = {
href: attachment.href,
- httpHeaders: attachment.httpHeaders
+ httpHeaders: attachment.httpHeaders,
+ tls: attachment.tls
};
} else {
data.content = attachment.content || '';
@@ -160,18 +161,7 @@ class MailComposer {
});
if (this.mail.icalEvent) {
- if (
- typeof this.mail.icalEvent === 'object' &&
- (this.mail.icalEvent.content || this.mail.icalEvent.path || this.mail.icalEvent.href || this.mail.icalEvent.raw)
- ) {
- icalEvent = this.mail.icalEvent;
- } else {
- icalEvent = {
- content: this.mail.icalEvent
- };
- }
-
- eventObject = Object.assign({}, icalEvent);
+ eventObject = Object.assign({}, this._getIcalEvent());
eventObject.contentType = 'application/ics';
if (!eventObject.headers) {
@@ -195,6 +185,67 @@ class MailComposer {
};
}
+ /**
+ * Returns the icalEvent value with `path`/`href`/data uri input normalized into
+ * a `content` entry, the same way as for regular attachments. The same event is
+ * included twice (as a text/calendar alternative and as an application/ics
+ * attachment), so the shared content object is marked to be resolved just once
+ * and the buffered result is reused by the second node.
+ *
+ * @returns {Object} Normalized icalEvent data
+ */
+ _getIcalEvent() {
+ if (!this._icalEvent) {
+ let icalEvent;
+ if (
+ typeof this.mail.icalEvent === 'object' &&
+ (this.mail.icalEvent.content || this.mail.icalEvent.path || this.mail.icalEvent.href || this.mail.icalEvent.raw)
+ ) {
+ icalEvent = Object.assign({}, this.mail.icalEvent);
+ } else {
+ icalEvent = {
+ content: this.mail.icalEvent
+ };
+ }
+
+ if (/^data:/i.test(icalEvent.path || icalEvent.href)) {
+ icalEvent = this._processDataUrl(icalEvent);
+ }
+
+ if (/^https?:\/\//i.test(icalEvent.path)) {
+ icalEvent.href = icalEvent.path;
+ icalEvent.path = undefined;
+ }
+
+ if (!icalEvent.raw) {
+ // map file path and URL values into `content`, otherwise the content
+ // nodes would render an empty body
+ if (icalEvent.path) {
+ icalEvent.content = {
+ path: icalEvent.path
+ };
+ icalEvent.path = undefined;
+ } else if (icalEvent.href) {
+ icalEvent.content = {
+ href: icalEvent.href,
+ httpHeaders: icalEvent.httpHeaders
+ };
+ icalEvent.href = undefined;
+ }
+ }
+
+ if (icalEvent.content && typeof icalEvent.content === 'object') {
+ // we are going to have the same attachment twice, so mark this to be
+ // resolved just once
+ icalEvent.content._resolve = true;
+ }
+
+ this._icalEvent = icalEvent;
+ }
+
+ return this._icalEvent;
+ }
+
/**
* List alternatives. Resulting objects can be used as input for MimeNode nodes
*
@@ -202,7 +253,7 @@ class MailComposer {
*/
getAlternatives() {
const alternatives = [];
- let text, html, watchHtml, amp, icalEvent, eventObject;
+ let text, html, watchHtml, amp, eventObject;
if (this.mail.text) {
if (
@@ -248,24 +299,7 @@ class MailComposer {
// NB! when including attachments with a calendar alternative you might end up in a blank screen on some clients
if (this.mail.icalEvent) {
- if (
- typeof this.mail.icalEvent === 'object' &&
- (this.mail.icalEvent.content || this.mail.icalEvent.path || this.mail.icalEvent.href || this.mail.icalEvent.raw)
- ) {
- icalEvent = this.mail.icalEvent;
- } else {
- icalEvent = {
- content: this.mail.icalEvent
- };
- }
-
- eventObject = Object.assign({}, icalEvent);
-
- if (eventObject.content && typeof eventObject.content === 'object') {
- // we are going to have the same attachment twice, so mark this to be
- // resolved just once
- eventObject.content._resolve = true;
- }
+ eventObject = Object.assign({}, this._getIcalEvent());
eventObject.filename = false;
eventObject.contentType =
diff --git a/node_modules/nodemailer/lib/mailer/index.js b/node_modules/nodemailer/lib/mailer/index.js
index 971438ba..cb40f7b5 100644
--- a/node_modules/nodemailer/lib/mailer/index.js
+++ b/node_modules/nodemailer/lib/mailer/index.js
@@ -8,7 +8,7 @@ const DKIM = require('../dkim');
const httpProxyClient = require('../smtp-connection/http-proxy-client');
const errors = require('../errors');
const util = require('util');
-const urllib = require('url');
+const urllib = require('../shared/url');
const packageData = require('../../package.json');
const MailMessage = require('./mail-message');
const net = require('net');
@@ -324,7 +324,7 @@ class Mail extends EventEmitter {
// Connect using a HTTP CONNECT method
case 'http':
case 'https':
- httpProxyClient(proxy.href, options.port, options.host, (err, socket) => {
+ httpProxyClient(proxy.href, options.port, options.host, this.options.tls || {}, (err, socket) => {
if (err) {
return callback(err);
}
@@ -407,31 +407,39 @@ class Mail extends EventEmitter {
if ((!this.options.attachDataUrls && !mail.data.attachDataUrls) || !mail.data.html) {
return callback();
}
- mail.resolveContent(mail.data, 'html', (err, html) => {
- if (err) {
- return callback(err);
+ mail.resolveContent(
+ mail.data,
+ 'html',
+ { disableFileAccess: mail.data.disableFileAccess, disableUrlAccess: mail.data.disableUrlAccess },
+ (err, html) => {
+ if (err) {
+ return callback(err);
+ }
+ let cidCounter = 0;
+ html = (html || '')
+ .toString()
+ .replace(
+ /(
]{0,1024} src\s{0,20}=[\s"']{0,20})(data:([^;]+);[^"'>\s]+)/gi,
+ (match, prefix, dataUri, mimeType) => {
+ const cid = crypto.randomBytes(10).toString('hex') + '@localhost';
+ if (!mail.data.attachments) {
+ mail.data.attachments = [];
+ }
+ if (!Array.isArray(mail.data.attachments)) {
+ mail.data.attachments = [].concat(mail.data.attachments || []);
+ }
+ mail.data.attachments.push({
+ path: dataUri,
+ cid,
+ filename: 'image-' + ++cidCounter + '.' + mimeTypes.detectExtension(mimeType)
+ });
+ return prefix + 'cid:' + cid;
+ }
+ );
+ mail.data.html = html;
+ callback();
}
- let cidCounter = 0;
- html = (html || '')
- .toString()
- .replace(/(
]{0,1024} src\s{0,20}=[\s"']{0,20})(data:([^;]+);[^"'>\s]+)/gi, (match, prefix, dataUri, mimeType) => {
- const cid = crypto.randomBytes(10).toString('hex') + '@localhost';
- if (!mail.data.attachments) {
- mail.data.attachments = [];
- }
- if (!Array.isArray(mail.data.attachments)) {
- mail.data.attachments = [].concat(mail.data.attachments || []);
- }
- mail.data.attachments.push({
- path: dataUri,
- cid,
- filename: 'image-' + ++cidCounter + '.' + mimeTypes.detectExtension(mimeType)
- });
- return prefix + 'cid:' + cid;
- });
- mail.data.html = html;
- callback();
- });
+ );
}
set(key, value) {
diff --git a/node_modules/nodemailer/lib/mailer/mail-message.js b/node_modules/nodemailer/lib/mailer/mail-message.js
index a88df32c..83544d9d 100644
--- a/node_modules/nodemailer/lib/mailer/mail-message.js
+++ b/node_modules/nodemailer/lib/mailer/mail-message.js
@@ -111,25 +111,29 @@ class MailMessage {
if (!args[0] || !args[0][args[1]]) {
return resolveNext();
}
- shared.resolveContent(...args, (err, value) => {
- if (err) {
- return callback(err);
- }
+ shared.resolveContent(
+ ...args,
+ { disableFileAccess: this.data.disableFileAccess, disableUrlAccess: this.data.disableUrlAccess },
+ (err, value) => {
+ if (err) {
+ return callback(err);
+ }
- const node = {
- content: value
- };
- if (args[0][args[1]] && typeof args[0][args[1]] === 'object' && !Buffer.isBuffer(args[0][args[1]])) {
- Object.keys(args[0][args[1]]).forEach(key => {
- if (!(key in node) && !['content', 'path', 'href', 'raw'].includes(key)) {
- node[key] = args[0][args[1]][key];
- }
- });
- }
+ const node = {
+ content: value
+ };
+ if (args[0][args[1]] && typeof args[0][args[1]] === 'object' && !Buffer.isBuffer(args[0][args[1]])) {
+ Object.keys(args[0][args[1]]).forEach(key => {
+ if (!(key in node) && !['content', 'path', 'href', 'raw'].includes(key)) {
+ node[key] = args[0][args[1]][key];
+ }
+ });
+ }
- args[0][args[1]] = node;
- resolveNext();
- });
+ args[0][args[1]] = node;
+ resolveNext();
+ }
+ );
};
setImmediate(() => resolveNext());
@@ -269,18 +273,24 @@ class MailMessage {
if (value && value.url) {
if (key.toLowerCase().trim() === 'id') {
// List-ID: "comment"
- let comment = value.comment || '';
+ // strip CR/LF so a comment can't inject extra header lines
+ let comment = (value.comment || '').toString().replace(/\r?\n|\r/g, ' ');
if (mimeFuncs.isPlainText(comment)) {
comment = '"' + comment + '"';
} else {
comment = mimeFuncs.encodeWord(comment);
}
- return (value.comment ? comment + ' ' : '') + this._formatListUrl(value.url).replace(/^<[^:]+\/{,2}/, '');
+ // List-ID expects a bare domain-like identifier, so strip the
+ // scheme prefix that _formatListUrl adds or passes through
+ return (
+ (value.comment ? comment + ' ' : '') + this._formatListUrl(value.url).replace(/^<[^:]+:\/{0,2}/, '<')
+ );
}
// List-*: (comment)
- let comment = value.comment || '';
+ // strip CR/LF so a comment can't inject extra header lines
+ let comment = (value.comment || '').toString().replace(/\r?\n|\r/g, ' ');
if (!mimeFuncs.isPlainText(comment)) {
comment = mimeFuncs.encodeWord(comment);
}
diff --git a/node_modules/nodemailer/lib/mime-funcs/mime-types.js b/node_modules/nodemailer/lib/mime-funcs/mime-types.js
index 126db62e..11096430 100644
--- a/node_modules/nodemailer/lib/mime-funcs/mime-types.js
+++ b/node_modules/nodemailer/lib/mime-funcs/mime-types.js
@@ -2087,7 +2087,7 @@ module.exports = {
if (!mimeType) {
return defaultExtension;
}
- const parts = (mimeType || '').toLowerCase().trim().split('/');
+ const parts = mimeType.toLowerCase().trim().split('/');
const rootType = parts.shift().trim();
const subType = parts.join('/').trim();
diff --git a/node_modules/nodemailer/lib/mime-node/index.js b/node_modules/nodemailer/lib/mime-node/index.js
index 586b268a..f000cb62 100644
--- a/node_modules/nodemailer/lib/mime-node/index.js
+++ b/node_modules/nodemailer/lib/mime-node/index.js
@@ -1006,7 +1006,7 @@ class MimeNode {
return contentStream;
}
// fetch URL
- return nmfetch(content.href, { headers: content.httpHeaders });
+ return nmfetch(content.href, { headers: content.httpHeaders, tls: content.tls });
}
// pass string or buffer content as a stream
diff --git a/node_modules/nodemailer/lib/nodemailer.js b/node_modules/nodemailer/lib/nodemailer.js
index 379a7506..140803b3 100644
--- a/node_modules/nodemailer/lib/nodemailer.js
+++ b/node_modules/nodemailer/lib/nodemailer.js
@@ -95,12 +95,22 @@ module.exports.createTestAccount = function (apiUrl, callback) {
requestHeaders.Authorization = 'Bearer ' + ETHEREAL_API_KEY;
}
- const req = nmfetch(apiUrl + '/user', {
+ const fetchOptions = {
contentType: 'application/json',
method: 'POST',
headers: requestHeaders,
body: Buffer.from(JSON.stringify(requestBody))
- });
+ };
+
+ // Credential-bearing request to the Ethereal API. lib/fetch already
+ // validates certs by default; pin rejectUnauthorized:true here so this
+ // call stays strict regardless of any future default change and is never
+ // relaxed for a real-cert endpoint.
+ if (/^https:/i.test(apiUrl)) {
+ fetchOptions.tls = { rejectUnauthorized: true };
+ }
+
+ const req = nmfetch(apiUrl + '/user', fetchOptions);
req.on('readable', () => {
let chunk;
@@ -137,11 +147,20 @@ module.exports.getTestMessageUrl = function (info) {
}
const infoProps = new Map();
- info.response.replace(/\[([^\]]+)\]$/, (m, props) => {
- props.replace(/\b([A-Z0-9]+)=([^\s]+)/g, (m, key, value) => {
- infoProps.set(key, value);
- });
- });
+
+ // Extract the trailing "[...]" part of the response (no "]" allowed inside)
+ // with linear string scanning; the equivalent regex /\[([^\]]+)\]$/ was
+ // flagged for polynomial backtracking on adversarial server responses
+ const response = info.response.toString();
+ if (response.length > 2 && response.charAt(response.length - 1) === ']') {
+ const open = response.indexOf('[', response.lastIndexOf(']', response.length - 2) + 1);
+ if (open >= 0 && open < response.length - 2) {
+ const props = response.substring(open + 1, response.length - 1);
+ props.replace(/\b([A-Z0-9]+)=([^\s]+)/g, (m, key, value) => {
+ infoProps.set(key, value);
+ });
+ }
+ }
if (infoProps.has('STATUS') && infoProps.has('MSGID')) {
return (testAccount.web || ETHEREAL_WEB) + '/message/' + infoProps.get('MSGID');
diff --git a/node_modules/nodemailer/lib/sendmail-transport/index.js b/node_modules/nodemailer/lib/sendmail-transport/index.js
index 8be9db5f..b89d5dd2 100644
--- a/node_modules/nodemailer/lib/sendmail-transport/index.js
+++ b/node_modules/nodemailer/lib/sendmail-transport/index.js
@@ -4,6 +4,8 @@ const { spawn } = require('child_process');
const packageData = require('../../package.json');
const shared = require('../shared');
const errors = require('../errors');
+const LeWindows = require('../mime-node/le-windows');
+const LeUnix = require('../mime-node/le-unix');
/**
* Generates a Transport object for Sendmail
@@ -46,6 +48,8 @@ class SendmailTransport {
this.args = options.args;
}
}
+
+ this.winbreak = ['win', 'windows', 'dos', '\r\n'].includes((options.newline || '').toString().toLowerCase());
}
/**
@@ -178,7 +182,15 @@ class SendmailTransport {
);
const sourceStream = mail.message.createReadStream();
- sourceStream.once('error', err => {
+ let stream = sourceStream;
+ if (this.options.newline) {
+ // apply the transport-level line ending transform; the message-level
+ // `newline` option is handled by MimeNode in createReadStream()
+ stream = sourceStream.pipe(this.winbreak ? new LeWindows() : new LeUnix());
+ sourceStream.once('error', err => stream.emit('error', err));
+ }
+
+ stream.once('error', err => {
this.logger.error(
{
err,
@@ -193,7 +205,7 @@ class SendmailTransport {
callback(err);
});
- sourceStream.pipe(sendmail.stdin);
+ stream.pipe(sendmail.stdin);
} else {
const err = new Error('sendmail was not found');
err.code = errors.ESENDMAIL;
diff --git a/node_modules/nodemailer/lib/ses-transport/index.js b/node_modules/nodemailer/lib/ses-transport/index.js
index 3f966aa2..4b5892cb 100644
--- a/node_modules/nodemailer/lib/ses-transport/index.js
+++ b/node_modules/nodemailer/lib/ses-transport/index.js
@@ -3,9 +3,22 @@
const EventEmitter = require('events');
const packageData = require('../../package.json');
const shared = require('../shared');
+const errors = require('../errors');
const LeWindows = require('../mime-node/le-windows');
const MimeNode = require('../mime-node');
+/**
+ * Tags AWS SDK rejections that carry no `code` property (SDK v3 errors only
+ * have a `name`) with the generic SES transport error code, keeping the
+ * original error object intact
+ */
+function tagSesError(err) {
+ if (err && typeof err === 'object' && !err.code) {
+ err.code = errors.ESES;
+ }
+ return err;
+}
+
/**
* Generates a Transport object for AWS SES
*
@@ -157,6 +170,7 @@ class SESTransport extends EventEmitter {
});
})
.catch(err => {
+ tagSesError(err);
this.logger.error(
{
err,
@@ -188,7 +202,7 @@ class SESTransport extends EventEmitter {
const cb = err => {
if (err && !['InvalidParameterValue', 'MessageRejected'].includes(err.code || err.Code || err.name)) {
- return callback(err);
+ return callback(tagSesError(err));
}
return callback(null, true);
};
@@ -205,15 +219,13 @@ class SESTransport extends EventEmitter {
}
};
- this.getRegion((err, region) => {
- if (err || !region) {
- region = 'us-east-1';
- }
-
+ // the region value is not used for anything when verifying, but the lookup
+ // exercises the client configuration the same way as send() does
+ this.getRegion(() => {
const command = new this.ses.SendEmailCommand(sesMessage);
const sendPromise = this.ses.sesClient.send(command);
- sendPromise.then(data => cb(null, data)).catch(err => cb(err));
+ sendPromise.then(() => cb(null)).catch(err => cb(err));
});
return promise;
diff --git a/node_modules/nodemailer/lib/shared/index.js b/node_modules/nodemailer/lib/shared/index.js
index 2f923c2b..8918fcf4 100644
--- a/node_modules/nodemailer/lib/shared/index.js
+++ b/node_modules/nodemailer/lib/shared/index.js
@@ -2,10 +2,11 @@
'use strict';
-const urllib = require('url');
+const urllib = require('./url');
const util = require('util');
const fs = require('fs');
const nmfetch = require('../fetch');
+const errors = require('../errors');
const dns = require('dns');
const net = require('net');
const os = require('os');
@@ -366,7 +367,16 @@ module.exports._logFunc = (logger, level, defaults, data, message, ...args) => {
const entry = Object.assign({}, defaults || {}, data || {});
delete entry.level;
- logger[level](entry, message, ...args);
+ let logLevel = level;
+ if (typeof logger[logLevel] !== 'function') {
+ // Provided logger does not implement this level. Fall back to a
+ // lower-severity handler instead of throwing.
+ logLevel = ['info', 'debug', 'log', 'trace', 'warn', 'error'].find(name => typeof logger[name] === 'function');
+ }
+
+ if (logLevel) {
+ logger[logLevel](entry, message, ...args);
+ }
};
/**
@@ -501,9 +511,17 @@ module.exports.parseDataURI = uri => {
*
* @param {Object} data An object or an Array you want to resolve an element for
* @param {String|Number} key Property name or an Array index
+ * @param {Object} [options] Optional access policy: { disableFileAccess, disableUrlAccess }
* @param {Function} callback Callback function with (err, value)
*/
-module.exports.resolveContent = (data, key, callback) => {
+module.exports.resolveContent = (data, key, options, callback) => {
+ // options is optional; support the legacy resolveContent(data, key, callback) signature
+ if (!callback && typeof options === 'function') {
+ callback = options;
+ options = false;
+ }
+ options = options || {};
+
let promise;
if (!callback) {
@@ -512,6 +530,12 @@ module.exports.resolveContent = (data, key, callback) => {
});
}
+ resolveContentValue(data, key, options, callback);
+
+ return promise;
+};
+
+function resolveContentValue(data, key, options, callback) {
let content = (data && data[key] && data[key].content) || data[key];
const encoding = ((typeof data[key] === 'object' && data[key].encoding) || 'utf8')
.toString()
@@ -538,15 +562,26 @@ module.exports.resolveContent = (data, key, callback) => {
callback(null, value);
});
} else if (/^https?:\/\//i.test(content.path || content.href)) {
- return resolveStream(nmfetch(content.path || content.href), callback);
+ if (options.disableUrlAccess) {
+ return setImmediate(() => {
+ const err = new Error('Url access rejected for ' + (content.path || content.href));
+ err.code = errors.EURLACCESS;
+ callback(err);
+ });
+ }
+ return resolveStream(nmfetch(content.path || content.href, { headers: content.httpHeaders, tls: content.tls }), callback);
} else if (/^data:/i.test(content.path || content.href)) {
const parsedDataUri = module.exports.parseDataURI(content.path || content.href);
- if (!parsedDataUri || !parsedDataUri.data) {
- return callback(null, Buffer.from(0));
- }
- return callback(null, parsedDataUri.data);
+ return callback(null, parsedDataUri && parsedDataUri.data ? parsedDataUri.data : Buffer.alloc(0));
} else if (content.path) {
+ if (options.disableFileAccess) {
+ return setImmediate(() => {
+ const err = new Error('File access rejected for ' + content.path);
+ err.code = errors.EFILEACCESS;
+ callback(err);
+ });
+ }
return resolveStream(fs.createReadStream(content.path), callback);
}
}
@@ -557,9 +592,7 @@ module.exports.resolveContent = (data, key, callback) => {
// default action, return as is
setImmediate(() => callback(null, content));
-
- return promise;
-};
+}
/**
* Copies properties from source objects to target objects
diff --git a/node_modules/nodemailer/lib/shared/url.js b/node_modules/nodemailer/lib/shared/url.js
new file mode 100644
index 00000000..116d5566
--- /dev/null
+++ b/node_modules/nodemailer/lib/shared/url.js
@@ -0,0 +1,151 @@
+'use strict';
+
+// URL parsing wrapper. Prefers the WHATWG `URL` (a global on Node 10+, and
+// available as `require('url').URL` since Node 6.13+) and only falls back to the
+// legacy, deprecation-warning-emitting `url.parse()` / `url.resolve()` on ancient
+// Node versions that predate the WHATWG implementation.
+//
+// The WHATWG `URL` exposes a different shape than the legacy parser, so results
+// are normalized back into the legacy field names the rest of the codebase reads
+// (`protocol`, `hostname`, `port`, `pathname`, `path`, `search`, `auth`, `query`,
+// `href`). This keeps every existing call site unchanged.
+//
+// Known, accepted divergences from the legacy parser:
+// - non-special schemes (smtp:/smtps:/direct:) are not host-lowercased by
+// WHATWG; cosmetic only, SMTP/DNS hosts are case-insensitive. (IDNA mapping
+// and IPv6 brackets are normalized back by normalizeHostname below.)
+// - a literal unescaped ':' inside a password is percent-encoded by WHATWG;
+// such passwords should be percent-encoded by the caller anyway.
+
+const urllib = require('url');
+const punycode = require('../punycode');
+
+// WHATWG URL constructor if available, otherwise undefined (Node < 6.13).
+const URLImpl = (typeof URL !== 'undefined' && URL) || urllib.URL;
+
+// Matches a "scheme:" not followed by "//" (and with something after it), used
+// to re-insert the authority separator the legacy parser did not require.
+const SLASHLESS_AUTHORITY = /^([a-zA-Z][a-zA-Z0-9+.-]*:)(?!\/\/)(.+)$/;
+
+// decodeURIComponent that never throws. Legacy url.parse() decodes the auth
+// component but tolerates malformed percent sequences, so mirror that.
+function safeDecode(str) {
+ try {
+ return decodeURIComponent(str);
+ } catch (_err) {
+ return str;
+ }
+}
+
+// Derives the legacy-shaped bare hostname from a WHATWG URL. WHATWG keeps IPv6
+// literals bracketed ('[::1]') and, for non-special schemes (smtp:/smtps:/socks:),
+// percent-encodes a non-ASCII host instead of IDNA-mapping it. Both forms are
+// un-resolvable when handed to net/dns/http.request — which is what every call
+// site does — so map them back to what legacy url.parse() returned: the bare
+// address and the punycode form. Idempotent on plain ASCII and already-punycode
+// hosts, so special-scheme hosts (already IDNA-mapped by WHATWG) pass through.
+function normalizeHostname(raw) {
+ let hostname = raw || '';
+ if (!hostname) {
+ // Host-less URL (e.g. 'direct:'): legacy returned '' here, not null;
+ // consumers do `hostname.length` / `'.' + hostname`, so keep it a string.
+ return '';
+ }
+ if (hostname.charAt(0) === '[' && hostname.charAt(hostname.length - 1) === ']') {
+ return hostname.slice(1, -1);
+ }
+ return punycode.toASCII(safeDecode(hostname));
+}
+
+module.exports.parse = (input, parseQueryString) => {
+ input = input || '';
+
+ if (!URLImpl) {
+ // Node < 6.13: no WHATWG URL available, use the legacy parser.
+ return urllib.parse(input, parseQueryString);
+ }
+
+ // Legacy url.parse() parses a "user:pass@host:port" authority that follows
+ // the scheme even without the "//" separator, for schemes outside its
+ // built-in slashed-protocol list (smtp:/smtps:/socks:/...). The WHATWG
+ // parser instead treats a scheme not followed by "//" as an opaque path.
+ // Re-insert the "//" so slash-less connection/proxy URLs keep resolving to
+ // an authority, as they did before. This assumes a slash-authority scheme,
+ // which every consumer here uses (http/https/smtp/smtps/socks/direct); an
+ // opaque scheme like mailto:/data:/tel: would be mis-split, but none reach
+ // this module.
+ const slashless = SLASHLESS_AUTHORITY.exec(input);
+ const normalized = slashless ? slashless[1] + '//' + slashless[2] : input;
+
+ let u;
+ try {
+ u = new URLImpl(normalized);
+ } catch (_err) {
+ // WHATWG rejects some input the legacy parser tolerated (empty/relative
+ // strings, scheme-relative '//host/path', out-of-range ports, ...). Fall
+ // back to the legacy parser so behavior — including the downstream errors
+ // callers rely on — is preserved. This is the only path that can still
+ // emit a deprecation warning; it fires for anything WHATWG cannot
+ // represent, including legitimate relative URLs, not just malformed input.
+ return urllib.parse(input, parseQueryString);
+ }
+
+ const hostname = normalizeHostname(u.hostname);
+ const port = u.port || null;
+ const pathname = u.pathname || null;
+ const search = u.search || null;
+
+ // Legacy `.auth` is the decoded "user[:pass]" string; WHATWG keeps the
+ // username/password percent-encoded, so decode to stay byte-compatible with
+ // existing consumers (parseConnectionUrl, Basic/Proxy-Authorization headers).
+ let auth = null;
+ if (u.username || u.password) {
+ // Gate on password too: legacy url.parse('smtps://:pass@host').auth was
+ // ':pass'. Dropping it would silently connect unauthenticated.
+ auth = safeDecode(u.username) + (u.password ? ':' + safeDecode(u.password) : '');
+ }
+
+ let query;
+ if (parseQueryString) {
+ // Mirror querystring.parse(): null-prototype object, repeated keys → array.
+ query = Object.create(null);
+ u.searchParams.forEach((value, key) => {
+ if (Object.prototype.hasOwnProperty.call(query, key)) {
+ if (Array.isArray(query[key])) {
+ query[key].push(value);
+ } else {
+ query[key] = [query[key], value];
+ }
+ } else {
+ query[key] = value;
+ }
+ });
+ } else {
+ query = search ? search.slice(1) : null;
+ }
+
+ return {
+ protocol: u.protocol || null,
+ host: u.host || null,
+ hostname,
+ port,
+ pathname,
+ search,
+ path: (pathname || '') + (search || '') || null,
+ href: u.href,
+ auth,
+ query
+ };
+};
+
+module.exports.resolve = (from, to) => {
+ if (!URLImpl) {
+ return urllib.resolve(from, to);
+ }
+ try {
+ return new URLImpl(to, from).href;
+ } catch (_err) {
+ // Malformed target — fall back to the legacy resolver.
+ return urllib.resolve(from, to);
+ }
+};
diff --git a/node_modules/nodemailer/lib/smtp-connection/http-proxy-client.js b/node_modules/nodemailer/lib/smtp-connection/http-proxy-client.js
index 36cd4bd8..4dc70132 100644
--- a/node_modules/nodemailer/lib/smtp-connection/http-proxy-client.js
+++ b/node_modules/nodemailer/lib/smtp-connection/http-proxy-client.js
@@ -6,7 +6,7 @@
const net = require('net');
const tls = require('tls');
-const urllib = require('url');
+const urllib = require('../shared/url');
const errors = require('../errors');
/**
@@ -19,20 +19,29 @@ const errors = require('../errors');
* @param {String} proxyUrl proxy configuration, etg "http://proxy.host:3128/"
* @param {Number} destinationPort Port to open in destination host
* @param {String} destinationHost Destination hostname
+ * @param {Object} [tlsOptions] Optional TLS options for an HTTPS proxy (e.g. { rejectUnauthorized: false })
* @param {Function} callback Callback to run with the rocket object once connection is established
*/
-function httpProxyClient(proxyUrl, destinationPort, destinationHost, callback) {
+function httpProxyClient(proxyUrl, destinationPort, destinationHost, tlsOptions, callback) {
+ if (typeof tlsOptions === 'function') {
+ callback = tlsOptions;
+ tlsOptions = {};
+ }
+ tlsOptions = tlsOptions || {};
+
const proxy = urllib.parse(proxyUrl);
- const options = {
+ const connectOptions = {
host: proxy.hostname,
port: Number(proxy.port) ? Number(proxy.port) : proxy.protocol === 'https:' ? 443 : 80
};
let connect;
if (proxy.protocol === 'https:') {
- // we can use untrusted proxies as long as we verify actual SMTP certificates
- options.rejectUnauthorized = false;
+ // Validate the proxy's TLS certificate by default. A caller that uses a
+ // self-signed proxy (e.g. integration tests) opts out explicitly with
+ // tls.rejectUnauthorized === false.
+ connectOptions.rejectUnauthorized = tlsOptions.rejectUnauthorized !== false;
connect = tls.connect.bind(tls);
} else {
connect = net.connect.bind(net);
@@ -62,7 +71,7 @@ function httpProxyClient(proxyUrl, destinationPort, destinationHost, callback) {
tempSocketErr(err);
};
- socket = connect(options, () => {
+ socket = connect(connectOptions, () => {
if (finished) {
return;
}
diff --git a/node_modules/nodemailer/lib/smtp-connection/index.js b/node_modules/nodemailer/lib/smtp-connection/index.js
index df5fd0a2..c201529c 100644
--- a/node_modules/nodemailer/lib/smtp-connection/index.js
+++ b/node_modules/nodemailer/lib/smtp-connection/index.js
@@ -51,9 +51,9 @@ function decodeServerResponse(str) {
* * **requireTLS** - forces the client to use STARTTLS
* * **name** - the name of the client server
* * **localAddress** - outbound address to bind to (see: http://nodejs.org/api/net.html#net_net_connect_options_connectionlistener)
- * * **greetingTimeout** - Time to wait in ms until greeting message is received from the server (defaults to 10000)
- * * **connectionTimeout** - how many milliseconds to wait for the connection to establish
- * * **socketTimeout** - Time of inactivity until the connection is closed (defaults to 1 hour)
+ * * **greetingTimeout** - Time to wait in ms until greeting message is received from the server (defaults to 30 seconds)
+ * * **connectionTimeout** - how many milliseconds to wait for the connection to establish (defaults to 2 minutes)
+ * * **socketTimeout** - Time of inactivity until the connection is closed (defaults to 10 minutes)
* * **dnsTimeout** - Time to wait in ms for the DNS requests to be resolved (defaults to 30 seconds)
* * **lmtp** - if true, uses LMTP instead of SMTP protocol
* * **logger** - bunyan compatible logger interface
@@ -211,6 +211,13 @@ class SMTPConnection extends EventEmitter {
*/
this._closing = false;
+ /**
+ * Message DATA stream currently piped to the socket, if any. Tracked so
+ * close() can unpipe it before tearing the socket down.
+ * @private
+ */
+ this._currentDataStream = false;
+
/**
* Callbacks for socket's listeners
*/
@@ -470,6 +477,17 @@ class SMTPConnection extends EventEmitter {
const socket = (this._socket && this._socket.socket) || this._socket;
+ // Detach any in-flight DATA stream from the socket so the source stream
+ // can be garbage-collected once the socket is gone.
+ if (this._currentDataStream) {
+ try {
+ this._currentDataStream.unpipe(this._socket);
+ } catch (_E) {
+ // ignore
+ }
+ this._currentDataStream = false;
+ }
+
if (socket && !socket.destroyed) {
try {
// Clear socket timeout to prevent timer leaks
@@ -820,7 +838,7 @@ class SMTPConnection extends EventEmitter {
return;
}
- let data = (chunk || '').toString('binary');
+ let data = chunk.toString('binary');
let lines = (this._remainder + data).split(/\r?\n/);
let lastline;
@@ -953,7 +971,9 @@ class SMTPConnection extends EventEmitter {
*/
_onEnd() {
if (this._socket && !this._socket.destroyed) {
- this._socket.destroy();
+ // Peer sent FIN — finish our half of the close gracefully rather
+ // than destroying. 'close' fires after the OS finalizes teardown.
+ this._socket.end();
}
}
@@ -1005,6 +1025,15 @@ class SMTPConnection extends EventEmitter {
opts.servername = this.servername;
}
+ // Remove all listeners from the plain socket to allow proper garbage
+ // collection. Used on both the TLS-success path and the synchronous
+ // tls.connect() throw path; either way the plain socket is done.
+ const removePlainSocketListeners = () => {
+ socketPlain.removeListener('close', this._onSocketClose);
+ socketPlain.removeListener('end', this._onSocketEnd);
+ socketPlain.removeListener('error', this._onSocketError);
+ };
+
this.upgrading = true;
// tls.connect is not an asynchronous function however it may still throw errors and requires to be wrapped with try/catch
try {
@@ -1013,14 +1042,12 @@ class SMTPConnection extends EventEmitter {
this.upgrading = false;
this._socket.on('data', this._onSocketData);
- // Remove all listeners from the plain socket to allow proper garbage collection
- socketPlain.removeListener('close', this._onSocketClose);
- socketPlain.removeListener('end', this._onSocketEnd);
- socketPlain.removeListener('error', this._onSocketError);
+ removePlainSocketListeners();
return callback(null, true);
});
} catch (err) {
+ removePlainSocketListeners();
return callback(err);
}
@@ -1297,6 +1324,7 @@ class SMTPConnection extends EventEmitter {
});
}
+ this._currentDataStream = dataStream;
dataStream.pipe(this._socket, {
end: false
});
@@ -1318,6 +1346,9 @@ class SMTPConnection extends EventEmitter {
}
dataStream.once('end', () => {
+ if (this._currentDataStream === dataStream) {
+ this._currentDataStream = false;
+ }
this.logger.info(
{
tnx: 'message',
diff --git a/node_modules/nodemailer/lib/smtp-transport/index.js b/node_modules/nodemailer/lib/smtp-transport/index.js
index 5988fc22..bc07616f 100644
--- a/node_modules/nodemailer/lib/smtp-transport/index.js
+++ b/node_modules/nodemailer/lib/smtp-transport/index.js
@@ -71,13 +71,19 @@ class SMTPTransport extends EventEmitter {
getAuth(authOpts) {
if (!authOpts) {
+ if (this.auth && this.auth.oauth2 && this.mailer) {
+ // Transport-level auth is resolved in the constructor, before the Mail wrapper
+ // assigns `this.mailer`, so a provision callback registered with
+ // `transporter.set('oauth2_provision_cb', ...)` has to be re-checked here
+ this.auth.oauth2.provisionCallback = this.mailer.get('oauth2_provision_cb') || this.auth.oauth2.provisionCallback;
+ }
return this.auth;
}
const authData = Object.assign(
{},
this.options.auth && typeof this.options.auth === 'object' ? this.options.auth : {},
- authOpts && typeof authOpts === 'object' ? authOpts : {}
+ typeof authOpts === 'object' ? authOpts : {}
);
if (Object.keys(authData).length === 0) {
@@ -151,11 +157,20 @@ class SMTPTransport extends EventEmitter {
const connection = new SMTPConnection(options);
+ let perCallAuth;
+ const cleanupPerCallAuth = () => {
+ if (perCallAuth && perCallAuth !== this.auth && perCallAuth.oauth2) {
+ perCallAuth.oauth2.removeAllListeners();
+ }
+ perCallAuth = null;
+ };
+
connection.once('error', err => {
if (returned) {
return;
}
returned = true;
+ cleanupPerCallAuth();
connection.close();
return callback(err);
});
@@ -170,6 +185,7 @@ class SMTPTransport extends EventEmitter {
return;
}
returned = true;
+ cleanupPerCallAuth();
// still have not returned, this means we have an unexpected connection close
const err = new Error('Unexpected socket close');
if (connection && connection._socket && connection._socket.upgrading) {
@@ -216,6 +232,7 @@ class SMTPTransport extends EventEmitter {
connection.send(envelope, mail.message.createReadStream(), (err, info) => {
returned = true;
+ cleanupPerCallAuth();
connection.close();
if (err) {
this.logger.error(
@@ -255,13 +272,11 @@ class SMTPTransport extends EventEmitter {
return;
}
- const auth = this.getAuth(mail.data.auth);
+ perCallAuth = this.getAuth(mail.data.auth);
- if (auth && (connection.allowsAuth || options.forceAuth)) {
- connection.login(auth, err => {
- if (auth && auth !== this.auth && auth.oauth2) {
- auth.oauth2.removeAllListeners();
- }
+ if (perCallAuth && (connection.allowsAuth || options.forceAuth)) {
+ connection.login(perCallAuth, err => {
+ cleanupPerCallAuth();
if (returned) {
return;
}
@@ -323,12 +338,20 @@ class SMTPTransport extends EventEmitter {
const connection = new SMTPConnection(options);
let returned = false;
+ let perCallAuth;
+ const cleanupPerCallAuth = () => {
+ if (perCallAuth && perCallAuth !== this.auth && perCallAuth.oauth2) {
+ perCallAuth.oauth2.removeAllListeners();
+ }
+ perCallAuth = null;
+ };
connection.once('error', err => {
if (returned) {
return;
}
returned = true;
+ cleanupPerCallAuth();
connection.close();
return callback(err);
});
@@ -338,6 +361,7 @@ class SMTPTransport extends EventEmitter {
return;
}
returned = true;
+ cleanupPerCallAuth();
return callback(new Error('Connection closed'));
});
@@ -346,6 +370,7 @@ class SMTPTransport extends EventEmitter {
return;
}
returned = true;
+ cleanupPerCallAuth();
connection.quit();
return callback(null, true);
};
@@ -355,10 +380,11 @@ class SMTPTransport extends EventEmitter {
return;
}
- const authData = this.getAuth({});
+ perCallAuth = this.getAuth({});
- if (authData && (connection.allowsAuth || options.forceAuth)) {
- connection.login(authData, err => {
+ if (perCallAuth && (connection.allowsAuth || options.forceAuth)) {
+ connection.login(perCallAuth, err => {
+ cleanupPerCallAuth();
if (returned) {
return;
}
@@ -371,11 +397,12 @@ class SMTPTransport extends EventEmitter {
finalize();
});
- } else if (!authData && connection.allowsAuth && options.forceAuth) {
+ } else if (!perCallAuth && connection.allowsAuth && options.forceAuth) {
const err = new Error('Authentication info was not provided');
err.code = errors.ENOAUTH;
returned = true;
+ cleanupPerCallAuth();
connection.close();
return callback(err);
} else {
diff --git a/node_modules/nodemailer/lib/stream-transport/index.js b/node_modules/nodemailer/lib/stream-transport/index.js
index 08d5ebd7..c000111f 100644
--- a/node_modules/nodemailer/lib/stream-transport/index.js
+++ b/node_modules/nodemailer/lib/stream-transport/index.js
@@ -2,6 +2,8 @@
const packageData = require('../../package.json');
const shared = require('../shared');
+const LeWindows = require('../mime-node/le-windows');
+const LeUnix = require('../mime-node/le-unix');
/**
* Generates a Transport object for streaming
@@ -63,6 +65,13 @@ class StreamTransport {
try {
stream = mail.message.createReadStream();
+ if (this.options.newline) {
+ // apply the transport-level line ending transform; the message-level
+ // `newline` option is handled by MimeNode in createReadStream()
+ const sourceStream = stream;
+ stream = sourceStream.pipe(this.winbreak ? new LeWindows() : new LeUnix());
+ sourceStream.once('error', err => stream.emit('error', err));
+ }
} catch (E) {
this.logger.error(
{
diff --git a/node_modules/nodemailer/lib/xoauth2/index.js b/node_modules/nodemailer/lib/xoauth2/index.js
index c1321db2..7c262fb0 100644
--- a/node_modules/nodemailer/lib/xoauth2/index.js
+++ b/node_modules/nodemailer/lib/xoauth2/index.js
@@ -33,6 +33,7 @@ const errors = require('../errors');
* @param {Number} options.expires Optional Access Token expire time in ms
* @param {Number} options.timeout Optional TTL for Access Token in seconds
* @param {Function} options.provisionCallback Function to run when a new access token is required
+ * @param {Object} options.tls Optional TLS options forwarded to the HTTPS token request. Defaults to strict cert validation; supply { rejectUnauthorized: false } only for self-hosted OAuth providers on private CAs.
*/
class XOAuth2 extends Stream {
constructor(options, logger) {
@@ -370,12 +371,23 @@ class XOAuth2 extends Stream {
const chunks = [];
let chunklen = 0;
- const req = nmfetch(url, {
+ const fetchOptions = {
method: 'post',
headers: params.customHeaders,
body: payload,
allowErrorResponse: true
- });
+ };
+
+ // OAuth2 token endpoints are credential-bearing. lib/fetch already
+ // validates certs by default; pin rejectUnauthorized:true here so the
+ // token fetch stays strict, while still layering params.tls (the
+ // user's options.tls) on top so callers with a self-hosted provider on
+ // a private CA can override.
+ if (/^https:/i.test(url)) {
+ fetchOptions.tls = Object.assign({ rejectUnauthorized: true }, params.tls || {});
+ }
+
+ const req = nmfetch(url, fetchOptions);
req.on('readable', () => {
let chunk;
diff --git a/node_modules/nodemailer/package.json b/node_modules/nodemailer/package.json
index 5e7bb627..4c07b1fb 100644
--- a/node_modules/nodemailer/package.json
+++ b/node_modules/nodemailer/package.json
@@ -1,11 +1,11 @@
{
"name": "nodemailer",
- "version": "8.0.7",
+ "version": "9.0.0",
"description": "Easy as cake e-mail sending from your Node.js applications",
"main": "lib/nodemailer.js",
"scripts": {
- "test": "node --test --test-concurrency=1 test/**/*.test.js test/**/*-test.js",
- "test:coverage": "c8 node --test --test-concurrency=1 test/**/*.test.js test/**/*-test.js",
+ "test": "node --test --test-concurrency=1 $(find test \\( -name '*-test.js' -o -name '*.test.js' \\))",
+ "test:coverage": "c8 node --test --test-concurrency=1 $(find test \\( -name '*-test.js' -o -name '*.test.js' \\))",
"format": "prettier --write \"**/*.{js,json,md}\"",
"format:check": "prettier --check \"**/*.{js,json,md}\"",
"lint": "eslint .",
@@ -27,19 +27,19 @@
},
"homepage": "https://nodemailer.com/",
"devDependencies": {
- "@aws-sdk/client-sesv2": "3.1037.0",
+ "@aws-sdk/client-sesv2": "3.1065.0",
"bunyan": "1.8.15",
"c8": "11.0.0",
- "eslint": "10.2.1",
+ "eslint": "10.4.1",
"eslint-config-prettier": "10.1.8",
- "globals": "17.5.0",
+ "globals": "17.6.0",
"libbase64": "1.3.0",
"libmime": "5.3.8",
"libqp": "2.1.1",
- "prettier": "3.8.3",
+ "prettier": "3.8.4",
"proxy": "1.0.2",
"proxy-test-server": "1.0.0",
- "smtp-server": "3.18.4"
+ "smtp-server": "3.18.5"
},
"engines": {
"node": ">=6.0.0"