mirror of
https://github.com/dawidd6/action-send-mail.git
synced 2026-09-29 04:20:39 +07:00
node_modules: update (#325)
Co-authored-by: dawidd6 <9713907+dawidd6@users.noreply.github.com>
This commit is contained in:
+53
-8
@@ -85,6 +85,29 @@ function _isWordCode(code) {
|
||||
function _isBoundary(text, at) {
|
||||
return _isWordCode(text.charCodeAt(at - 1)) !== _isWordCode(text.charCodeAt(at));
|
||||
}
|
||||
/**
|
||||
* Offset of the first '@' in `text` between `from` and `to`, or -1 when the range holds none.
|
||||
*
|
||||
* indexOf would scan on to the end of the value, and the value here is a whole header. The
|
||||
* walk below steps one whitespace delimited run at a time and only ever uses a '@' that sits
|
||||
* inside the run it is on, so an unbounded probe rescans everything behind that run once per
|
||||
* run and grows with the square of the header: 400KB of free text carrying no '@' took a
|
||||
* quarter of a second. GHSA-v53p-9fqp-m79j took the pattern search out of this walk and left
|
||||
* the probe unbounded behind it.
|
||||
*
|
||||
* @param text Text to look in
|
||||
* @param from Offset to start at
|
||||
* @param to Offset to stop before
|
||||
* @return Offset of the '@', or -1
|
||||
*/
|
||||
function _indexOfAt(text, from, to) {
|
||||
for (let i = from; i < to; i++) {
|
||||
if (text.charCodeAt(i) === 0x40) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
/**
|
||||
* Finds the offset LOOSE_TEXT_ADDR matches at, or -1 when it does not match at all.
|
||||
*
|
||||
@@ -115,8 +138,8 @@ function _looseAddressStart(text) {
|
||||
while (runEnd < len && !_isSpaceCode(text.charCodeAt(runEnd))) {
|
||||
runEnd++;
|
||||
}
|
||||
let at = text.indexOf('@', runStart);
|
||||
if (at >= 0 && at < runEnd) {
|
||||
let at = _indexOfAt(text, runStart, runEnd);
|
||||
if (at >= 0) {
|
||||
let lastBoundary = -1;
|
||||
for (let k = runEnd; k > runStart; k--) {
|
||||
if (_isBoundary(text, k)) {
|
||||
@@ -125,7 +148,7 @@ function _looseAddressStart(text) {
|
||||
}
|
||||
}
|
||||
let atomStart = runStart;
|
||||
while (lastBoundary >= 0 && at >= 0 && at < runEnd) {
|
||||
while (lastBoundary >= 0 && at >= 0) {
|
||||
// '[^@\s]+' has to cover a character before the '@' and '[^\s]+' one after it,
|
||||
// and the boundary that ends the match has to sit past both
|
||||
if (at > atomStart && runEnd > at + 1 && lastBoundary > at + 1) {
|
||||
@@ -145,7 +168,7 @@ function _looseAddressStart(text) {
|
||||
}
|
||||
}
|
||||
atomStart = at + 1;
|
||||
at = text.indexOf('@', atomStart);
|
||||
at = _indexOfAt(text, atomStart, runEnd);
|
||||
}
|
||||
}
|
||||
pos = runEnd;
|
||||
@@ -272,6 +295,19 @@ function _handleAddress(tokens, depth) {
|
||||
}
|
||||
}
|
||||
else if (token.value) {
|
||||
// An empty quoted string is dropped by the tokenizer, leaving no text token of its
|
||||
// own for textWasQuoted to be recorded on, so the pair of quote operators right in
|
||||
// front of this token is all that is left of it and the run it opens carries the
|
||||
// quoting instead. Without this '""@example.com' reads as the bare '@example.com',
|
||||
// the quotes never go back on, and the value is no longer an addr-spec a trailing
|
||||
// comment can be peeled off of. It only ever opens a run: a run that already holds
|
||||
// material collected outside the quotes is not a quoted string, whatever follows it
|
||||
const prevPrevToken = i > 1 ? tokens[i - 2] : null;
|
||||
const opensAfterEmptyQuotedString = prevToken?.type === 'operator' &&
|
||||
prevToken.value === '"' &&
|
||||
!!prevToken.noBreak &&
|
||||
prevPrevToken?.type === 'operator' &&
|
||||
prevPrevToken.value === '"';
|
||||
if (state === 'address') {
|
||||
// Handle unquoted name that includes a "<".
|
||||
// Apple Mail truncates everything between an unexpected < and an address.
|
||||
@@ -299,7 +335,7 @@ function _handleAddress(tokens, depth) {
|
||||
data[state].push(token.value);
|
||||
lastChars[state] = token.value.charAt(token.value.length - 1);
|
||||
if (state === 'text') {
|
||||
data.textWasQuoted.push(insideQuotes);
|
||||
data.textWasQuoted.push(insideQuotes || opensAfterEmptyQuotedString);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -384,6 +420,18 @@ function _handleAddress(tokens, depth) {
|
||||
// Join values with spaces
|
||||
data.text = data.text.join(' ');
|
||||
data.address = data.address.join(' ');
|
||||
if (addressFromQuotedText && data.text) {
|
||||
// The mailbox is still sitting in the text, so it moves over here and is quoted
|
||||
// before the recovery below rather than after it. Anything else the text holds
|
||||
// came along with it: a comment ends the domain but leaves the atoms behind it in
|
||||
// the same text, and '"user"@example.com(x)evil.com' was handed on as the address
|
||||
// 'user@example.com evil.com', a second domain riding into the envelope recipient
|
||||
// on a value that is no addr-spec at all (GHSA-g57g-f23g-4646). Putting the quotes
|
||||
// back first is what lets the recovery tell the whitespace an addr-spec may carry
|
||||
// from the wreckage trailing one, as only a quoted local part may hold whitespace
|
||||
data.address = _quoteLocalPart(data.text);
|
||||
data.text = '';
|
||||
}
|
||||
_recoverAddrSpec(data);
|
||||
const address = {
|
||||
address: data.address || data.text || '',
|
||||
@@ -397,9 +445,6 @@ function _handleAddress(tokens, depth) {
|
||||
address.address = '';
|
||||
}
|
||||
}
|
||||
if (addressFromQuotedText && address.address) {
|
||||
address.address = _quoteLocalPart(address.address);
|
||||
}
|
||||
addresses.push(address);
|
||||
}
|
||||
return addresses;
|
||||
|
||||
Reference in New Issue
Block a user