mirror of
https://github.com/dawidd6/action-send-mail.git
synced 2026-09-29 12:28:07 +07:00
node_modules: update (#325)
Co-authored-by: dawidd6 <9713907+dawidd6@users.noreply.github.com>
This commit is contained in:
+3
@@ -41,6 +41,8 @@ export interface SMTPConnectionOptions {
|
||||
greetingTimeout?: number | undefined;
|
||||
/** Time of inactivity in ms until the connection is closed, defaults to 10 minutes */
|
||||
socketTimeout?: number | undefined;
|
||||
/** Largest single server response to accept in bytes, defaults to 1 MB */
|
||||
maxResponseSize?: number | undefined;
|
||||
/** Time to wait in ms for the DNS requests to be resolved, defaults to 30 seconds */
|
||||
dnsTimeout?: number | undefined;
|
||||
/** Use LMTP instead of SMTP */
|
||||
@@ -268,6 +270,7 @@ export type SMTPConnectionResponseAction = (str: string) => void;
|
||||
* * **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)
|
||||
* * **maxResponseSize** - Largest single server response to accept in bytes (defaults to 1 MB)
|
||||
* * **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
|
||||
|
||||
+62
-18
@@ -51,6 +51,9 @@ const SOCKET_TIMEOUT = 10 * 60 * 1000; // how much to wait for socket inactivity
|
||||
const GREETING_TIMEOUT = 30 * 1000; // how much to wait after connection is established but SMTP greeting is not receieved
|
||||
const DNS_TIMEOUT = 30 * 1000; // how much to wait for resolveHostname
|
||||
const TEARDOWN_NOOP = () => { }; // reusable no-op handler for absorbing errors during socket teardown
|
||||
// how many bytes a single server response may occupy while it is still being received.
|
||||
// Generous compared to any real reply, it only stops a peer that never completes one
|
||||
const MAX_RESPONSE_SIZE = 1024 * 1024;
|
||||
/**
|
||||
* Re-interpret a server response stored in fake 8-bit byte-container form
|
||||
* (the result of chunk.toString('binary') in _onData) as UTF-8.
|
||||
@@ -79,11 +82,19 @@ function decodeServerResponse(str) {
|
||||
* Called with the byte-container form the queue holds (see _onData): the check only looks
|
||||
* at leading ASCII digits and '-' of the last line, and a UTF-8 continuation byte is never
|
||||
* 0x0A, so line boundaries and the tested prefix are the same before and after decoding.
|
||||
* The last line is read with lastIndexOf rather than split() because a queue entry grows
|
||||
* with every chunk appended to it and only its final line matters.
|
||||
* The last line is read with lastIndexOf rather than split() because a queue entry may hold
|
||||
* a whole multiline reply and only its final line matters.
|
||||
*/
|
||||
function isPartialResponse(str) {
|
||||
return /^\d+-/.test(str.slice(str.lastIndexOf('\n') + 1));
|
||||
return isPartialLine(str.slice(str.lastIndexOf('\n') + 1));
|
||||
}
|
||||
/**
|
||||
* True when a single reply line is a continuation ("250-..."). Used where the line is
|
||||
* already known to be one line, which skips the scan isPartialResponse needs to find the
|
||||
* last line of a whole reply.
|
||||
*/
|
||||
function isPartialLine(line) {
|
||||
return /^\d+-/.test(line);
|
||||
}
|
||||
/**
|
||||
* Generates a SMTP connection object
|
||||
@@ -100,6 +111,7 @@ function isPartialResponse(str) {
|
||||
* * **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)
|
||||
* * **maxResponseSize** - Largest single server response to accept in bytes (defaults to 1 MB)
|
||||
* * **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
|
||||
@@ -146,6 +158,7 @@ class SMTPConnection extends node_events_1.EventEmitter {
|
||||
this.secure = !!this.secureConnection;
|
||||
this._remainder = '';
|
||||
this._responseQueue = [];
|
||||
this._responsePartial = false;
|
||||
this.lastServerResponse = false;
|
||||
this._socket = false;
|
||||
this._supportedAuth = [];
|
||||
@@ -714,28 +727,58 @@ class SMTPConnection extends node_events_1.EventEmitter {
|
||||
if (this._destroyed || !chunk || !chunk.length) {
|
||||
return;
|
||||
}
|
||||
let data = chunk.toString('binary');
|
||||
let lines = (this._remainder + data).split(/\r?\n/);
|
||||
let lastline;
|
||||
const maxResponseSize = this.options.maxResponseSize || MAX_RESPONSE_SIZE;
|
||||
const data = chunk.toString('binary');
|
||||
// A chunk without a line break only extends the line currently being received, so
|
||||
// keep it in the remainder and leave that string unflattened. Splitting the whole
|
||||
// remainder again on every chunk would rescan everything buffered for that line so
|
||||
// far, which is quadratic in the length of a line the peer never terminates
|
||||
if (!data.includes('\n')) {
|
||||
this._remainder += data;
|
||||
if (this._remainder.length > maxResponseSize) {
|
||||
return this._onResponseTooLarge();
|
||||
}
|
||||
return;
|
||||
}
|
||||
const lines = (this._remainder + data).split(/\r?\n/);
|
||||
this._remainder = lines.pop();
|
||||
for (let i = 0, len = lines.length; i < len; i++) {
|
||||
if (this._responseQueue.length) {
|
||||
lastline = this._responseQueue[this._responseQueue.length - 1];
|
||||
if (isPartialResponse(lastline)) {
|
||||
this._responseQueue[this._responseQueue.length - 1] += '\n' + lines[i];
|
||||
continue;
|
||||
}
|
||||
if (this._responsePartial) {
|
||||
this._responseQueue[this._responseQueue.length - 1] += '\n' + lines[i];
|
||||
}
|
||||
else {
|
||||
this._responseQueue.push(lines[i]);
|
||||
}
|
||||
// The line just added is the last line of that queue entry, so it alone decides
|
||||
// whether the reply is still partial. Looking for the last line of the accumulated
|
||||
// entry instead would rescan a string that grows with every continuation line,
|
||||
// which is quadratic in the size of the reply
|
||||
this._responsePartial = isPartialLine(lines[i]);
|
||||
// Checked as each line lands, so a peer that never completes a reply cannot keep
|
||||
// buffering, and the limit does not depend on how it split its bytes into chunks
|
||||
if (this._responsePartial && this._responseQueue[this._responseQueue.length - 1].length > maxResponseSize) {
|
||||
return this._onResponseTooLarge();
|
||||
}
|
||||
this._responseQueue.push(lines[i]);
|
||||
}
|
||||
if (this._responseQueue.length) {
|
||||
lastline = this._responseQueue[this._responseQueue.length - 1];
|
||||
if (isPartialResponse(lastline)) {
|
||||
return;
|
||||
}
|
||||
if (this._remainder.length > maxResponseSize) {
|
||||
return this._onResponseTooLarge();
|
||||
}
|
||||
if (this._responsePartial) {
|
||||
return;
|
||||
}
|
||||
this._processResponse();
|
||||
}
|
||||
/**
|
||||
* Drops a connection whose peer keeps extending a reply it never completes, releasing
|
||||
* whatever was buffered for that reply
|
||||
* @internal
|
||||
*/
|
||||
_onResponseTooLarge() {
|
||||
this._remainder = '';
|
||||
this._responseQueue = [];
|
||||
this._responsePartial = false;
|
||||
this._onError(new Error('Server response exceeds maximum allowed size'), 'EPROTOCOL', false, 'CONN');
|
||||
}
|
||||
/**
|
||||
* 'error' listener for the socket
|
||||
*
|
||||
@@ -876,6 +919,7 @@ class SMTPConnection extends node_events_1.EventEmitter {
|
||||
// part of the secured EHLO capabilities). STARTTLS response injection.
|
||||
this._remainder = '';
|
||||
this._responseQueue = [];
|
||||
this._responsePartial = false;
|
||||
// do not remove all listeners or it breaks node v0.10 as there's
|
||||
// apparently a 'finish' event set that would be cleared as well
|
||||
// we can safely keep 'error', 'end', 'close' etc. events
|
||||
|
||||
Reference in New Issue
Block a user