mirror of
https://github.com/dawidd6/action-send-mail.git
synced 2026-10-09 09:59:45 +07:00
node_modules: update (#340)
Co-authored-by: dawidd6 <9713907+dawidd6@users.noreply.github.com>
This commit is contained in:
1 parent
791f27c1e4
commit
0635835dfc
50 files changed
+835
-266
No files matched your search
-1
@@ -39,7 +39,6 @@ export type Address = MailboxAddress | GroupAddress;
|
||||
*
|
||||
* @param str Address field
|
||||
* @param options Optional options object
|
||||
* @param options._depth Internal recursion depth counter (do not set manually)
|
||||
* @return An array of address objects
|
||||
*/
|
||||
declare function addressparser(str: string | null | undefined, options: AddressParserOptions & {
|
||||
|
||||
+55
-17
@@ -428,7 +428,7 @@ function _handleAddress(tokens, depth) {
|
||||
// Parse group members, but flatten any nested groups (RFC 5322 doesn't allow nesting)
|
||||
let groupMembers = [];
|
||||
if (data.group.length) {
|
||||
const parsedGroup = addressparser(data.group.join(','), { _depth: depth + 1 });
|
||||
const parsedGroup = _parseAddressList(data.group.join(','), depth + 1);
|
||||
parsedGroup.forEach(member => {
|
||||
if (member.group) {
|
||||
groupMembers = groupMembers.concat(member.group);
|
||||
@@ -515,7 +515,13 @@ function _handleAddress(tokens, depth) {
|
||||
// Join values with spaces
|
||||
data.text = data.text.join(' ');
|
||||
data.address = data.address.join(' ');
|
||||
if (addressFromQuotedText && data.text) {
|
||||
if (addressFromQuotedText && data.text.indexOf('@') >= 0) {
|
||||
// A quoted run with no '@' in it is a display name and nothing else, so it stays
|
||||
// where it is. Moving it over anyway made a comment the mailbox was read from:
|
||||
// '"Display Name" <(a comment)>' handed on 'Display Name' as the address with the
|
||||
// comment as the name, and a quoted name holding a ',' or a ';' became an address
|
||||
// that reads as two recipients once a consumer writes it back into a header.
|
||||
//
|
||||
// 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
|
||||
@@ -562,6 +568,7 @@ class Tokenizer {
|
||||
this.node = null;
|
||||
this.escaped = false;
|
||||
this.inDomainLiteral = false;
|
||||
this.afterAt = false;
|
||||
this.list = [];
|
||||
/**
|
||||
* Operator tokens and which tokens are expected to end the sequence
|
||||
@@ -605,17 +612,23 @@ class Tokenizer {
|
||||
* Checks if a character is an operator or text and acts accordingly
|
||||
*
|
||||
* @param chr Character from the address field
|
||||
* @param nextChr Character following chr, null at the end of the field
|
||||
*/
|
||||
checkChar(chr, nextChr) {
|
||||
// Track RFC 5322 domain-literals ("[" *dtext "]"). Operator characters such
|
||||
// as the ":" of an IPv6 address-literal (user@[IPv6:2001:db8::1]) are dtext
|
||||
// and must not be treated as the group delimiter while inside the brackets.
|
||||
// Quoted strings and comments are handled separately via operatorExpecting,
|
||||
// so only enter this state when no operator is open. The list separators ","
|
||||
// and ";" are the exception: they always end the literal (and split the
|
||||
// address list) so that an unclosed "[" cannot swallow later recipients.
|
||||
// Track RFC 5322 domain-literals ("[" *dtext "]"). The ":" of an IPv6
|
||||
// address-literal (user@[IPv6:2001:db8::1]) is dtext and must not be treated as
|
||||
// the group delimiter while inside the brackets. That is the only operator the
|
||||
// literal hides: letting it hide the others as well meant a "[" could turn the
|
||||
// comment, quoted string or angle-addr after it into text and pick a different
|
||||
// mailbox, '[ ( ] <a@victim.com> ) <b@evil.com>' yielded a@victim.com where
|
||||
// RFC 5322 reads b@evil.com. A "[" also only opens a literal right after the "@"
|
||||
// of an addr-spec, so the group delimiter of a display name holding one stays
|
||||
// intact. Quoted strings and comments are handled separately via
|
||||
// operatorExpecting, so only enter this state when no operator is open. The list
|
||||
// separators "," and ";" always end the literal (and split the address list) so
|
||||
// that an unclosed "[" cannot swallow later recipients.
|
||||
if (!this.escaped && !this.operatorExpecting) {
|
||||
if (!this.inDomainLiteral && chr === '[') {
|
||||
if (!this.inDomainLiteral && chr === '[' && this.afterAt) {
|
||||
this.inDomainLiteral = true;
|
||||
}
|
||||
else if (this.inDomainLiteral && (chr === ']' || chr === ',' || chr === ';')) {
|
||||
@@ -635,17 +648,24 @@ class Tokenizer {
|
||||
}
|
||||
this.list.push(this.node);
|
||||
this.node = null;
|
||||
if (chr !== ')') {
|
||||
// a comment is folding whitespace, it does not part the "@" from the "["
|
||||
this.afterAt = false;
|
||||
}
|
||||
this.operatorExpecting = '';
|
||||
this.escaped = false;
|
||||
return;
|
||||
}
|
||||
else if (!this.operatorExpecting && !this.inDomainLiteral && chr in this.operators) {
|
||||
else if (!this.operatorExpecting && !(this.inDomainLiteral && chr === ':') && chr in this.operators) {
|
||||
this.node = {
|
||||
type: 'operator',
|
||||
value: chr
|
||||
};
|
||||
this.list.push(this.node);
|
||||
this.node = null;
|
||||
if (chr !== '(') {
|
||||
this.afterAt = false;
|
||||
}
|
||||
this.operatorExpecting = this.operators[chr];
|
||||
this.escaped = false;
|
||||
return;
|
||||
@@ -669,6 +689,11 @@ class Tokenizer {
|
||||
if (chr.charCodeAt(0) >= 0x21 || [' ', '\t'].includes(chr)) {
|
||||
// skip command bytes
|
||||
this.node.value += chr;
|
||||
// text inside a quoted string or a comment is not part of an addr-spec. Tracked
|
||||
// as it goes rather than read back off the value (see lastChars in _handleAddress)
|
||||
if (!this.operatorExpecting && chr !== ' ' && chr !== '\t') {
|
||||
this.afterAt = chr === '@';
|
||||
}
|
||||
}
|
||||
this.escaped = false;
|
||||
}
|
||||
@@ -679,9 +704,19 @@ class Tokenizer {
|
||||
* malicious input that could cause stack overflow.
|
||||
*/
|
||||
const MAX_NESTED_GROUP_DEPTH = 50;
|
||||
function addressparser(str, options) {
|
||||
options = options || {};
|
||||
const depth = options._depth || 0;
|
||||
/**
|
||||
* Parses an address list, recursing into the groups it holds.
|
||||
*
|
||||
* The depth is threaded through the calls rather than carried in an options object, so a
|
||||
* caller supplied one can not seed it and lift the recursion limit: `{ _depth: -1e9 }`
|
||||
* bought a billion levels of nesting and turned the guard below into the stack overflow it
|
||||
* is there to prevent.
|
||||
*
|
||||
* @param str Address field
|
||||
* @param depth Current recursion depth for nested group protection
|
||||
* @return An array of address objects
|
||||
*/
|
||||
function _parseAddressList(str, depth) {
|
||||
// Prevent stack overflow from deeply nested groups (DoS protection)
|
||||
if (depth > MAX_NESTED_GROUP_DEPTH) {
|
||||
return [];
|
||||
@@ -690,7 +725,7 @@ function addressparser(str, options) {
|
||||
const tokens = tokenizer.tokenize();
|
||||
const addresses = [];
|
||||
let address = [];
|
||||
let parsedAddresses = [];
|
||||
const parsedAddresses = [];
|
||||
tokens.forEach(token => {
|
||||
if (token.type === 'operator' && (token.value === ',' || token.value === ';')) {
|
||||
if (address.length) {
|
||||
@@ -731,8 +766,11 @@ function addressparser(str, options) {
|
||||
}
|
||||
}
|
||||
mergedAddresses.reverse();
|
||||
parsedAddresses = mergedAddresses;
|
||||
if (options.flatten) {
|
||||
return mergedAddresses;
|
||||
}
|
||||
function addressparser(str, options) {
|
||||
const parsedAddresses = _parseAddressList(str, 0);
|
||||
if (options?.flatten) {
|
||||
const flatAddresses = [];
|
||||
const walkAddressList = (list) => {
|
||||
list.forEach(entry => {
|
||||
|
||||
Reference in new issue
Block a user