node_modules: update (#349)

Co-authored-by: dawidd6 <9713907+dawidd6@users.noreply.github.com>
This commit is contained in:
Dawid Dziurlaanddawidd6 authored and GitHub committed 2026-10-18 15:39:30 +02:00
1 parent 9d0c26ec8b
commit 0a1f5db16c
36 files changed
+1934 -648

No files matched your search

+97 -22
View File
@@ -26,6 +26,35 @@ const QUOTED_STRING = /^"(?:[^"\\]|\\[\s\S])*"$/;
// else goes into angle brackets so that the header can not be read as more addresses than
// the envelope carries
const PLAIN_ADDRESS = /^[^\s"(),:;<>@[\\\]]+@[^\s"(),:;<>@[\\\]]+$/;
/**
* A domain literal that ends an address, see _normalizeAddress
*/
const DOMAIN_LITERAL_TAIL = /@(\[[^[\]\\]*\])$/;
/**
* Removes the whitespace inside every <...> of a References value. A "<" with no ">" after
* it is left as it is. An index scan, the regex /<[^>]*>/g rescans the rest of the value
* from every such "<"
*
* @param value References header value
* @returns The value with the msg-ids closed up
*/
function stripWhitespaceInAngleBrackets(value) {
let result = '';
let pos = 0;
for (;;) {
const open = value.indexOf('<', pos);
if (open < 0) {
break;
}
const close = value.indexOf('>', open + 1);
if (close < 0) {
break;
}
result += value.slice(pos, open) + value.slice(open, close + 1).replace(/\s/g, '');
pos = close + 1;
}
return result + value.slice(pos);
}
// domainToASCII and domainToUnicode are WHATWG host parsers rather than plain IDNA
// mappers, so they do more than map: they cut the host at '/', '\\', '?' and '#', drop C0
// controls, and percent-decode. Handing them 'evil.example/mail.corp.example' returns the
@@ -33,6 +62,13 @@ const PLAIN_ADDRESS = /^[^\s"(),:;<>@[\\\]]+@[^\s"(),:;<>@[\\\]]+$/;
// unroutable garbage into mail for a domain the sender never named. None of these
// characters are legal in a domain, so keep them away from the mapper.
const URL_PARSER_UNSAFE = /[/\\?#%\x00-\x20\x7F]/;
// RFC 1035 bounds a label at 63 octets and a domain at 253. An A-label is never shorter than
// the code points it encodes, so anything past these bounds could not have become a valid
// domain whichever way it is encoded. The bundled codec is super-linear in the length of a
// label, a 60 KB label of distinct code points took seconds to encode, several times per
// address, so it is only handed what could be a domain
const MAX_DOMAIN_LENGTH = 253;
const MAX_LABEL_LENGTH = 63;
// pipeline() needs a callback to not throw, the errors it sees reach the last stream anyway
const PIPELINE_NOOP = () => false;
// The error a node streaming into an output that was destroyed stops with
@@ -41,6 +77,27 @@ function abortedError() {
err.code = errors.ESTREAM;
return err;
}
/**
* Checks a domain against the DNS length limits, counted in code points per label and in
* total. The label separators are the ones the bundled codec splits on.
*
* @param domain Domain to check
* @return true if a label or the domain as a whole is too long to be a valid domain
*/
function exceedsDomainLimits(domain) {
let total = 0;
let label = 0;
for (const char of domain) {
total++;
if (char === '.' || char === '。' || char === '.' || char === '。') {
label = 0;
}
else if (++label > MAX_LABEL_LENGTH) {
return true;
}
}
return total > MAX_DOMAIN_LENGTH;
}
/**
* Encodes a domain the way browsers, the WHATWG URL Standard and DNS facing resolvers do,
* which is with UTS-46 mapping applied before the Punycode step.
@@ -72,6 +129,10 @@ function normalizeDomain(domain, toUnicode) {
return mapped;
}
}
if (exceedsDomainLimits(domain)) {
// too long to be a domain whichever way it is encoded, keep it as supplied
return domain;
}
return toUnicode ? punycode.toUnicode(domain) : punycode.toASCII(domain);
}
/**
@@ -576,6 +637,17 @@ class MimeNode {
/[\u0080-\uFFFF]/.test(this.content)) {
structured.params.charset = 'utf-8';
}
if (this.filename) {
// the name parameter is derived from the filename below, so a name that
// arrived inside the content type is dropped first (a plain parameter or
// rfc2231 continuation sections), otherwise the header carries two and a
// receiver that reads the first sees a name the filename does not match
for (const paramKey of Object.keys(structured.params)) {
if (/^name(\*|$)/i.test(paramKey)) {
delete structured.params[paramKey];
}
}
}
value = mimeFuncs.buildHeaderValue(structured);
if (this.filename) {
// add support for non-compliant clients like QQ webmail
@@ -1185,12 +1257,12 @@ class MimeNode {
_normalizeHeaderKey(key) {
key = (key || '')
.toString()
// no newlines in keys
.replace(/\r?\n|\r/g, ' ')
// a field name is printable ascii without the colon, so a control char or DEL
// can only be dropped, there is no quoting construct around a field name
.replace(/[\x00-\x1f\x7f]/g, '')
.trim()
// a field name is printable ascii without the colon, so a control char, DEL,
// whitespace or a colon can only be dropped, there is no quoting construct
// around a field name. A colon or a space left in place ends the name early on
// the wire: the key 'From: ceo@example.com (' with the value ')' was emitted as a
// second From header that neither setHeader() nor the Bcc filter could match
.replace(/[\s\x00-\x20\x7f:]/g, '')
.toLowerCase()
// use uppercase words, except MIME
.replace(/^X-SMTPAPI$|^(MIME|DKIM|ARC|BIMI)\b|^[a-z]|-(SPF|FBL|ID|MD5)$|-[a-z]/gi, c => c.toUpperCase())
@@ -1276,26 +1348,26 @@ class MimeNode {
}
return value;
// space separated list of values enclosed in <>
case 'References':
value = [].concat
.apply([], [].concat(value || '').map(elm => {
elm = (elm || '')
case 'References': {
const ids = [];
for (const entry of [].concat(value || '')) {
const elm = (entry || '')
.toString()
.replace(/\r?\n|\r/g, ' ')
.replace(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g, '')
.trim();
return elm.replace(/<[^>]*>/g, str => str.replace(/\s/g, '')).split(/\s+/);
}))
.map(elm => {
if (elm.charAt(0) !== '<') {
elm = '<' + elm;
for (let id of stripWhitespaceInAngleBrackets(elm).split(/\s+/)) {
if (id.charAt(0) !== '<') {
id = '<' + id;
}
if (id.charAt(id.length - 1) !== '>') {
id = id + '>';
}
ids.push(id);
}
if (elm.charAt(elm.length - 1) !== '>') {
elm = elm + '>';
}
return elm;
});
return value.join(' ').trim();
}
return ids.join(' ').trim();
}
case 'Date':
if (Object.prototype.toString.call(value) === '[object Date]') {
return value.toUTCString().replace(/GMT/, '+0000');
@@ -1374,7 +1446,10 @@ class MimeNode {
// callers use an empty value to detect a missing address
return address;
}
const lastAt = address.lastIndexOf('@');
// dtext includes '@', so a domain literal is split off at the '@' in front of it and
// not at the last one, which delivered 'a@[x@evil.com]' to evil.com
const literal = address.charAt(address.length - 1) === ']' ? DOMAIN_LITERAL_TAIL.exec(address) : null;
const lastAt = literal ? address.length - literal[1].length - 1 : address.lastIndexOf('@');
if (lastAt < 0) {
// Bare username, there is no domain to split off
return this._normalizeLocalPart(address);