node_modules: update (#314)

Co-authored-by: dawidd6 <9713907+dawidd6@users.noreply.github.com>
This commit is contained in:
Dawid Dziurla
2026-09-07 07:05:39 +02:00
committed by GitHub
parent 40eba5cee7
commit d35571df19
23 changed files with 938 additions and 176 deletions
+80 -19
View File
@@ -5,19 +5,39 @@
const base64 = require('../base64');
const qp = require('../qp');
const mimeTypes = require('./mime-types');
const { isProtoKey } = require('../shared/objects');
module.exports = {
/**
* Checks if a value is plaintext string (uses only printable 7bit chars)
*
* When isParam is set the value is destined for a header parameter, so HT, CR and LF
* are not plaintext either: a header parameter has no way to carry them. HT is a valid
* fold point, so folding and unfolding a header would rewrite it as a space, and CR/LF
* cannot appear in a header value at all. DEL is neither a token character nor qtext,
* so it can not be carried bare or quoted. Such values have to go through the rfc2231
* parameter continuation encoding instead, the same way a quote already does.
*
* @param {String} value String to be tested
* @param {Boolean} [isParam] Set to true if the value is a header parameter value
* @returns {Boolean} true if it is a plaintext string
*/
isPlainText(value, isParam) {
const re = isParam ? /[\x00-\x08\x0b\x0c\x0e-\x1f"\u0080-\uFFFF]/ : /[\x00-\x08\x0b\x0c\x0e-\x1f\u0080-\uFFFF]/;
const re = isParam ? /[\x00-\x1f\x7f"\u0080-\uFFFF]/ : /[\x00-\x08\x0b\x0c\x0e-\x1f\u0080-\uFFFF]/;
return typeof value === 'string' && !re.test(value);
},
/**
* Wraps a value into a quoted-string. Inside one a quote would end the string early
* and a backslash would escape whatever follows it, so both go out as quoted-pairs.
*
* @param {String} value String to be quoted
* @returns {String} The value as a quoted-string, quotes included
*/
quoteString(value) {
return '"' + (value || '').toString().replace(/["\\]/g, '\\$&') + '"';
},
/**
* Checks if a multi line string containes lines longer than the selected value.
*
@@ -80,8 +100,10 @@ module.exports = {
for (let i = 0, len = encodedStr.length; i < len; i++) {
let chr = encodedStr.charAt(i);
if (/[\ud83c\ud83d\ud83e]/.test(chr) && i < len - 1) {
// composite emoji byte, so add the next byte as well
if (/[\ud800-\udbff]/.test(chr) && /[\udc00-\udfff]/.test(encodedStr.charAt(i + 1))) {
// leading surrogate, so add the trailing surrogate as well
// an unpaired one must not swallow the next unit, that would destroy
// a valid pair following it
chr += encodedStr.charAt(++i);
}
@@ -168,10 +190,12 @@ module.exports = {
buildHeaderValue(structured) {
const paramsArray = [];
Object.keys(structured.params || {}).forEach(param => {
Object.keys(structured.params || {}).forEach(key => {
// filename might include unicode characters so it is a special case
// other values probably do not
const value = structured.params[param];
const value = structured.params[key];
// a parameter name is a token too and it is emitted without any quoting around it
const param = key.replace(/[\x00-\x1f\x7f]/g, '');
if (!this.isPlainText(value, true) || value.length >= 75) {
this.buildHeaderParam(param, value, 50).forEach(encodedParam => {
if (!/[\s"\\;:/=(),<>@[\]?]|^[-']|'$/.test(encodedParam.value) || encodedParam.key.substr(-1) === '*') {
@@ -187,7 +211,11 @@ module.exports = {
}
});
return structured.value + (paramsArray.length ? '; ' + paramsArray.join('; ') : '');
// the value ahead of the parameters is a token, it has no way to carry a control
// char or DEL and there is no quoting construct around it to escape one into
const value = typeof structured.value === 'string' ? structured.value.replace(/[\x00-\x1f\x7f]/g, '') : structured.value;
return value + (paramsArray.length ? '; ' + paramsArray.join('; ') : '');
},
/**
@@ -208,7 +236,7 @@ module.exports = {
buildHeaderParam(key, data, maxLength) {
const list = [];
let encodedStr = typeof data === 'string' ? data : (data || '').toString();
let chr, ord;
let chr;
let line;
let startPos = 0;
let i, len;
@@ -245,8 +273,9 @@ module.exports = {
const encodedStrArr = [];
for (i = 0, len = encodedStr.length; i < len; i++) {
chr = encodedStr.charAt(i);
ord = chr.charCodeAt(0);
if (ord >= 0xd800 && ord <= 0xdbff && i < len - 1) {
if (/[\ud800-\udbff]/.test(chr) && /[\udc00-\udfff]/.test(encodedStr.charAt(i + 1))) {
// an unpaired leading surrogate must not consume the next unit, that
// would tear apart a valid pair following it
chr += encodedStr.charAt(i + 1);
encodedStrArr.push(chr);
i++;
@@ -284,8 +313,11 @@ module.exports = {
line,
encoded
});
// the line we start here holds an encoded char, so it has to be
// flagged as one. otherwise it gets an unstarred continuation key
// and a receiver reads the percent escapes as literal text
line = '';
startPos = i - 1;
encoded = true;
} else {
encoded = true;
i = startPos;
@@ -350,6 +382,16 @@ module.exports = {
value: false,
params: {}
};
// Parameter names come from a caller supplied contentType/contentDisposition. A
// "__proto__" name would target the prototype chain of the params object instead of
// an own property of it, and read back as Object.prototype, so it is dropped.
const setParam = (name, value) => {
if (!isProtoKey(name)) {
response.params[name] = value;
}
};
let key = false;
let value = '';
let type = 'value';
@@ -381,7 +423,7 @@ module.exports = {
if (key === false) {
response.value = value.trim();
} else {
response.params[key] = value.trim();
setParam(key, value.trim());
}
type = 'key';
value = '';
@@ -396,10 +438,10 @@ module.exports = {
if (key === false) {
response.value = value.trim();
} else {
response.params[key] = value.trim();
setParam(key, value.trim());
}
} else if (value.trim()) {
response.params[value.trim().toLowerCase()] = '';
setParam(value.trim().toLowerCase(), '');
}
// handle parameter value continuations
@@ -412,6 +454,14 @@ module.exports = {
actualKey = key.substr(0, match.index);
nr = Number(match[2] || match[3]) || 0;
if (isProtoKey(actualKey)) {
// see setParam. Reading it back would yield Object.prototype, which is
// an object, so the initializer below would be skipped and the write
// that follows would throw out of a header build the caller can not catch
delete response.params[key];
return;
}
if (!response.params[actualKey] || typeof response.params[actualKey] !== 'object') {
response.params[actualKey] = {
charset: false,
@@ -538,7 +588,7 @@ module.exports = {
*/
splitMimeEncodedString: (str, maxlen) => {
const lines = [];
let curLine, match, chr, done;
let curLine, fallbackLine, match, chr, done;
// require at least 12 symbols to fit possible 4 octet UTF-8 sequences
maxlen = Math.max(maxlen || 0, 12);
@@ -551,8 +601,14 @@ module.exports = {
curLine = curLine.substr(0, match.index);
}
// Malformed input (a run of stray UTF-8 continuation bytes) has no split point
// that keeps a character sequence whole, so the loop below walks back to an
// empty line looking for one. Keep the widest chunk that at least does not cut
// a "=XX" escape in half, so the part stays a decodable encoded word.
fallbackLine = curLine.length ? curLine : str.substr(0, maxlen);
done = false;
while (!done) {
while (!done && curLine.length) {
done = true;
// check if not middle of a unicode char sequence
if ((match = str.substr(curLine.length).match(/^[=]([0-9A-F]{2})/i))) {
@@ -565,9 +621,11 @@ module.exports = {
}
}
if (curLine.length) {
lines.push(curLine);
if (!curLine.length) {
curLine = fallbackLine;
}
lines.push(curLine);
str = str.substr(curLine.length);
}
@@ -600,8 +658,11 @@ module.exports = {
// might throw if we try to encode invalid sequences, eg. partial emoji
str = encodeURIComponent(str);
} catch (_E) {
// should never run
return str.replace(/[^\x00-\x1F *'()<>@,;:\\"[\]?=\u007F-\uFFFF]+/g, '');
// an unpaired surrogate has no utf-8 representation, so run the value through a
// utf-8 roundtrip to get the same U+FFFD every other encoder here produces and
// retry. the value must never come back unencoded, it goes into a header parameter
// where a bare quote or semicolon would break it out into a parameter of its own
str = encodeURIComponent(Buffer.from(str, 'utf-8').toString('utf-8'));
}
// ensure chars that are not handled by encodeURICompent are converted as well