mirror of
https://github.com/dawidd6/action-send-mail.git
synced 2026-10-09 09:59:45 +07:00
node_modules: update (#332)
Co-authored-by: dawidd6 <9713907+dawidd6@users.noreply.github.com>
This commit is contained in:
1 parent
c1dac70e3a
commit
6bf0a2f26a
95 files changed
+1102
-503
No files matched your search
+2
-2
@@ -2,7 +2,7 @@
|
||||
* Minimal HTTP/S proxy client
|
||||
*/
|
||||
import net from 'node:net';
|
||||
import type { NodemailerError } from '../errors.js';
|
||||
import type { Callback } from '../errors.js';
|
||||
/**
|
||||
* TLS options for connecting to an HTTPS proxy
|
||||
*/
|
||||
@@ -13,7 +13,7 @@ export interface HttpProxyClientOptions {
|
||||
/**
|
||||
* Receives the proxied socket once the CONNECT handshake has succeeded, or the error that prevented it
|
||||
*/
|
||||
export type HttpProxyClientCallback = (err: NodemailerError | null, socket?: net.Socket) => void;
|
||||
export type HttpProxyClientCallback = Callback<net.Socket>;
|
||||
/**
|
||||
* Establishes proxied connection to destinationPort
|
||||
*
|
||||
|
||||
+6
-4
@@ -14,6 +14,8 @@ function httpProxyClient(proxyUrl, destinationPort, destinationHost, tlsOptions,
|
||||
tlsOptions = {};
|
||||
}
|
||||
tlsOptions = tlsOptions || {};
|
||||
// the error paths hand over the error alone
|
||||
const done = callback;
|
||||
// Reject CRLF in the destination before it reaches the CONNECT request line
|
||||
// and Host header. A tainted host/port could otherwise inject additional
|
||||
// request headers into the proxy connection (HTTP request splitting).
|
||||
@@ -21,7 +23,7 @@ function httpProxyClient(proxyUrl, destinationPort, destinationHost, tlsOptions,
|
||||
if (!destinationPort || /[\r\n]/.test(destinationHost)) {
|
||||
const err = new Error('Invalid proxy destination');
|
||||
err.code = errors.EPROXY;
|
||||
setImmediate(() => callback(err));
|
||||
setImmediate(() => done(err));
|
||||
return;
|
||||
}
|
||||
const proxy = urllib.parse(proxyUrl);
|
||||
@@ -55,7 +57,7 @@ function httpProxyClient(proxyUrl, destinationPort, destinationHost, tlsOptions,
|
||||
catch (_E) {
|
||||
// ignore
|
||||
}
|
||||
callback(err);
|
||||
done(err);
|
||||
};
|
||||
const timeoutErr = () => {
|
||||
const err = new Error('Proxy socket timed out');
|
||||
@@ -114,12 +116,12 @@ function httpProxyClient(proxyUrl, destinationPort, destinationHost, tlsOptions,
|
||||
}
|
||||
const err = new Error('Invalid response from proxy' + ((match && ': ' + match[1]) || ''));
|
||||
err.code = errors.EPROXY;
|
||||
return callback(err);
|
||||
return done(err);
|
||||
}
|
||||
socket.removeListener('error', tempSocketErr);
|
||||
socket.removeListener('timeout', timeoutErr);
|
||||
socket.setTimeout(0);
|
||||
return callback(null, socket);
|
||||
return done(null, socket);
|
||||
}
|
||||
if (headers.length > MAX_RESPONSE_HEADER_BYTES) {
|
||||
socket.removeListener('data', onSocketData);
|
||||
|
||||
+57
-22
@@ -3,8 +3,9 @@ import net from 'node:net';
|
||||
import tls from 'node:tls';
|
||||
import { type Readable } from 'node:stream';
|
||||
import * as shared from '../shared/index.js';
|
||||
import type { NodemailerError } from '../errors.js';
|
||||
import type { Callback, NodemailerError } from '../errors.js';
|
||||
import type XOAuth2 from '../xoauth2/index.js';
|
||||
import type { XOAuth2Options } from '../xoauth2/index.js';
|
||||
/**
|
||||
* Custom authentication handlers keyed by (case insensitive) SASL method name
|
||||
*/
|
||||
@@ -117,12 +118,23 @@ export interface SMTPConnectionCustomAuthResponse {
|
||||
* Callback for a command sent by a custom authentication handler
|
||||
*/
|
||||
export type SMTPConnectionCustomAuthCommandCallback = (err: Error | null, data: SMTPConnectionCustomAuthResponse) => void;
|
||||
/**
|
||||
* The auth object as a custom authentication handler sees it: the object handed to login()
|
||||
* with the credentials filled in from its user and pass values
|
||||
*/
|
||||
export interface SMTPConnectionCustomAuthData extends SMTPConnectionAuth {
|
||||
/** The user and pass values of the auth object, the way @types/nodemailer declared them */
|
||||
credentials: SMTPConnectionCredentials & {
|
||||
user: string;
|
||||
pass: string;
|
||||
};
|
||||
}
|
||||
/**
|
||||
* The object a custom authentication handler is run with
|
||||
*/
|
||||
export interface SMTPConnectionCustomAuthContext {
|
||||
/** The auth object handed to login() */
|
||||
auth: SMTPConnectionAuth;
|
||||
/** The auth object handed to login(), with the credentials filled in */
|
||||
auth: SMTPConnectionCustomAuthData;
|
||||
/** Selected authentication method name */
|
||||
method: string;
|
||||
/** SMTP extensions the server advertised */
|
||||
@@ -131,17 +143,20 @@ export interface SMTPConnectionCustomAuthContext {
|
||||
authMethods: string[];
|
||||
/** Maximum message size the server accepts, false when not advertised */
|
||||
maxAllowedSize: number | false;
|
||||
/** Sends a command to the server. Returns a promise when no callback is given */
|
||||
sendCommand(cmd: string, done?: SMTPConnectionCustomAuthCommandCallback): Promise<SMTPConnectionCustomAuthResponse> | undefined;
|
||||
/** Sends a command to the server and resolves with the parsed reply */
|
||||
sendCommand(cmd: string): Promise<SMTPConnectionCustomAuthResponse>;
|
||||
/** Sends a command to the server and hands the parsed reply to the callback */
|
||||
sendCommand(cmd: string, done: SMTPConnectionCustomAuthCommandCallback): void;
|
||||
/** Marks the user as authenticated */
|
||||
resolve(): void;
|
||||
/** Fails the authentication with an error */
|
||||
reject(err: Error | string): void;
|
||||
}
|
||||
/**
|
||||
* A custom authentication handler. Calls resolve() or reject() on the context, or returns a promise
|
||||
* A custom authentication handler. Calls resolve() or reject() on the context, or returns a
|
||||
* promise that settles the authentication. Any other return value is ignored
|
||||
*/
|
||||
export type SMTPConnectionCustomAuthHandler = (ctx: SMTPConnectionCustomAuthContext) => void | Promise<unknown>;
|
||||
export type SMTPConnectionCustomAuthHandler = (ctx: SMTPConnectionCustomAuthContext) => unknown;
|
||||
/**
|
||||
* An envelope address, either a plain string or an object with an address property
|
||||
*/
|
||||
@@ -168,12 +183,16 @@ export interface SMTPEnvelopeDsn {
|
||||
/** Alias of recipient, in the 'rfc822;address' form */
|
||||
orcpt?: string | null | undefined;
|
||||
}
|
||||
/**
|
||||
* A single DSN notify value
|
||||
*/
|
||||
export type SMTPEnvelopeDsnNotify = 'NEVER' | 'SUCCESS' | 'FAILURE' | 'DELAY';
|
||||
/**
|
||||
* Envelope object accepted by send()
|
||||
*/
|
||||
export interface SMTPEnvelope {
|
||||
/** Sender address */
|
||||
from?: string | SMTPEnvelopeAddress | undefined;
|
||||
/** Sender address, false for the null sender of a bounce message (MAIL FROM:<>) */
|
||||
from?: string | SMTPEnvelopeAddress | false | undefined;
|
||||
/** Recipient address or addresses */
|
||||
to?: string | SMTPEnvelopeAddress | Array<string | SMTPEnvelopeAddress> | undefined;
|
||||
/** Message size in bytes, sent as the SIZE parameter when the server supports it */
|
||||
@@ -202,9 +221,9 @@ export interface SMTPConnectionEnvelope extends SMTPEnvelope {
|
||||
accepted: string[];
|
||||
}
|
||||
/**
|
||||
* Result of a sent message
|
||||
* The recipient bookkeeping of a sent message, known once the envelope is accepted
|
||||
*/
|
||||
export interface SMTPConnectionSendInfo {
|
||||
export interface SMTPConnectionEnvelopeInfo {
|
||||
/** Recipients the server accepted */
|
||||
accepted: string[];
|
||||
/** Recipients the server rejected */
|
||||
@@ -213,19 +232,25 @@ export interface SMTPConnectionSendInfo {
|
||||
ehlo?: string[] | undefined;
|
||||
/** Errors for the rejected recipients */
|
||||
rejectedErrors?: NodemailerError[] | undefined;
|
||||
/** Time in ms spent on the envelope commands */
|
||||
envelopeTime?: number | undefined;
|
||||
/** Time in ms spent on streaming the message */
|
||||
messageTime?: number | undefined;
|
||||
/** Size of the encoded message in bytes */
|
||||
messageSize?: number | undefined;
|
||||
/** Final server response for the message */
|
||||
response?: string | undefined;
|
||||
}
|
||||
/**
|
||||
* Callback for send()
|
||||
* Result of a sent message
|
||||
*/
|
||||
export type SMTPConnectionSendCallback = (err: NodemailerError | null, info?: SMTPConnectionSendInfo) => void;
|
||||
export interface SMTPConnectionSendInfo extends SMTPConnectionEnvelopeInfo {
|
||||
/** Time in ms spent on the envelope commands */
|
||||
envelopeTime: number;
|
||||
/** Time in ms spent on streaming the message */
|
||||
messageTime: number;
|
||||
/** Size of the encoded message in bytes */
|
||||
messageSize: number;
|
||||
/** Final server response for the message */
|
||||
response: string;
|
||||
}
|
||||
/**
|
||||
* Callback for send(), receives the result once the server accepted the message. The error
|
||||
* path hands over the error alone
|
||||
*/
|
||||
export type SMTPConnectionSendCallback = Callback<SMTPConnectionSendInfo>;
|
||||
/**
|
||||
* Callback for login() and reset(), the result is true on success
|
||||
*/
|
||||
@@ -285,7 +310,7 @@ export type SMTPConnectionResponseAction = (str: string) => void;
|
||||
*/
|
||||
declare class SMTPConnection extends EventEmitter {
|
||||
id: string;
|
||||
stage: string;
|
||||
stage: 'init' | 'connected';
|
||||
options: SMTPConnectionOptions;
|
||||
secureConnection: boolean;
|
||||
alreadySecured: boolean;
|
||||
@@ -370,12 +395,22 @@ declare class SMTPConnection extends EventEmitter {
|
||||
declare namespace SMTPConnection {
|
||||
type Options = SMTPConnectionOptions;
|
||||
type AuthenticationType = SMTPConnectionAuth;
|
||||
type AuthenticationTypeLogin = SMTPConnectionAuth;
|
||||
type AuthenticationTypeOAuth2 = SMTPConnectionAuth;
|
||||
type AuthenticationTypeCustom = SMTPConnectionAuth;
|
||||
type AuthenticationCredentials = SMTPConnectionAuth;
|
||||
type AuthenticationOAuth2 = SMTPConnectionAuth;
|
||||
type Credentials = SMTPConnectionCredentials;
|
||||
type OAuth2 = XOAuth2Options;
|
||||
type Envelope = SMTPEnvelope;
|
||||
type DSNOptions = SMTPEnvelopeDsn;
|
||||
type DSNOption = SMTPEnvelopeDsnNotify;
|
||||
type SentMessageInfo = SMTPConnectionSendInfo;
|
||||
type SMTPError = NodemailerError;
|
||||
type CustomAuthenticationContext = SMTPConnectionCustomAuthContext;
|
||||
type CustomAuthenticationResponse = SMTPConnectionCustomAuthResponse;
|
||||
type CustomAuthenticationHandlers = SMTPConnectionCustomAuthHandlers;
|
||||
}
|
||||
/** The same aliases as module level exports, for `import * as SMTPConnection` and `import SMTPConnection = require()` */
|
||||
export type { SMTPConnectionOptions as Options, SMTPConnectionAuth as AuthenticationType, SMTPConnectionAuth as AuthenticationTypeLogin, SMTPConnectionAuth as AuthenticationTypeOAuth2, SMTPConnectionAuth as AuthenticationTypeCustom, SMTPConnectionAuth as AuthenticationCredentials, SMTPConnectionAuth as AuthenticationOAuth2, SMTPConnectionCredentials as Credentials, XOAuth2Options as OAuth2, SMTPEnvelope as Envelope, SMTPEnvelopeDsn as DSNOptions, SMTPEnvelopeDsnNotify as DSNOption, SMTPConnectionSendInfo as SentMessageInfo, NodemailerError as SMTPError, SMTPConnectionCustomAuthContext as CustomAuthenticationContext, SMTPConnectionCustomAuthResponse as CustomAuthenticationResponse, SMTPConnectionCustomAuthHandlers as CustomAuthenticationHandlers };
|
||||
export default SMTPConnection;
|
||||
+68
-55
@@ -414,14 +414,21 @@ class SMTPConnection extends EventEmitter {
|
||||
this._auth = authData || {};
|
||||
// Select SASL authentication method
|
||||
this._authMethod = (this._auth.method || '').toString().trim().toUpperCase() || false;
|
||||
// XOAUTH2 needs a token generator or a custom handler, without either the method
|
||||
// can not be run even when it is the only one the server advertised
|
||||
const canUseXOAuth2 = !!this._auth.oauth2 || this.customAuth.has('XOAUTH2');
|
||||
if (!this._authMethod && this._auth.oauth2 && !this._auth.credentials) {
|
||||
this._authMethod = 'XOAUTH2';
|
||||
}
|
||||
else if (!this._authMethod || (this._authMethod === 'XOAUTH2' && !this._auth.oauth2)) {
|
||||
// use first supported
|
||||
this._authMethod = (this._supportedAuth[0] || 'PLAIN').toUpperCase().trim();
|
||||
// use the first supported method that can be run
|
||||
const supported = this._supportedAuth.find(method => method !== 'XOAUTH2' || canUseXOAuth2);
|
||||
this._authMethod = (supported || 'PLAIN').toUpperCase().trim();
|
||||
}
|
||||
if (this._authMethod !== 'XOAUTH2' && (!this._auth.credentials || !this._auth.credentials.user || !this._auth.credentials.pass)) {
|
||||
// a token login needs no credentials, every other method and every custom handler
|
||||
// gets them filled in from the user and pass values
|
||||
if ((this._authMethod !== 'XOAUTH2' || this.customAuth.has('XOAUTH2')) &&
|
||||
(!this._auth.credentials || !this._auth.credentials.user || !this._auth.credentials.pass)) {
|
||||
if ((this._auth.user && this._auth.pass) || this.customAuth.has(this._authMethod)) {
|
||||
this._auth.credentials = {
|
||||
user: this._auth.user,
|
||||
@@ -458,42 +465,45 @@ class SMTPConnection extends EventEmitter {
|
||||
returned = true;
|
||||
callback(this._formatError(err, 'EAUTH', lastResponse, 'AUTH ' + this._authMethod));
|
||||
};
|
||||
// one implementation serves both sendCommand overloads, the promise is returned
|
||||
// exactly when no callback was given
|
||||
const sendCommand = (cmd, done) => {
|
||||
let promise;
|
||||
if (!done) {
|
||||
promise = new Promise((resolve, reject) => {
|
||||
done = shared.callbackPromise(resolve, reject);
|
||||
});
|
||||
}
|
||||
this._responseActions.push(str => {
|
||||
lastResponse = str;
|
||||
let codes = str.match(/^(\d+)(?:\s(\d+\.\d+\.\d+))?\s/);
|
||||
let data = {
|
||||
command: cmd,
|
||||
response: str
|
||||
};
|
||||
if (codes) {
|
||||
data.status = Number(codes[1]) || 0;
|
||||
if (codes[2]) {
|
||||
data.code = codes[2];
|
||||
}
|
||||
data.text = str.substr(codes[0].length);
|
||||
}
|
||||
else {
|
||||
data.text = str;
|
||||
data.status = 0; // just in case we need to perform numeric comparisons
|
||||
}
|
||||
done(null, data);
|
||||
});
|
||||
setImmediate(() => this._sendCommand(cmd));
|
||||
return promise;
|
||||
};
|
||||
const handlerResponse = handler({
|
||||
auth: this._auth,
|
||||
method: this._authMethod,
|
||||
extensions: [].concat(this._supportedExtensions),
|
||||
authMethods: [].concat(this._supportedAuth),
|
||||
maxAllowedSize: this._maxAllowedSize || false,
|
||||
sendCommand: (cmd, done) => {
|
||||
let promise;
|
||||
if (!done) {
|
||||
promise = new Promise((resolve, reject) => {
|
||||
done = shared.callbackPromise(resolve, reject);
|
||||
});
|
||||
}
|
||||
this._responseActions.push(str => {
|
||||
lastResponse = str;
|
||||
let codes = str.match(/^(\d+)(?:\s(\d+\.\d+\.\d+))?\s/);
|
||||
let data = {
|
||||
command: cmd,
|
||||
response: str
|
||||
};
|
||||
if (codes) {
|
||||
data.status = Number(codes[1]) || 0;
|
||||
if (codes[2]) {
|
||||
data.code = codes[2];
|
||||
}
|
||||
data.text = str.substr(codes[0].length);
|
||||
}
|
||||
else {
|
||||
data.text = str;
|
||||
data.status = 0; // just in case we need to perform numeric comparisons
|
||||
}
|
||||
done(null, data);
|
||||
});
|
||||
setImmediate(() => this._sendCommand(cmd));
|
||||
return promise;
|
||||
},
|
||||
sendCommand: sendCommand,
|
||||
resolve,
|
||||
reject
|
||||
});
|
||||
@@ -550,29 +560,30 @@ class SMTPConnection extends EventEmitter {
|
||||
* @param callback Callback to return once sending is completed
|
||||
*/
|
||||
send(envelope, message, done) {
|
||||
if (!message) {
|
||||
return done(this._formatError('Empty message', 'EMESSAGE', false, 'API'));
|
||||
}
|
||||
const isDestroyedMessage = this._isDestroyedMessage('send message');
|
||||
if (isDestroyedMessage) {
|
||||
return done(this._formatError(isDestroyedMessage, 'ECONNECTION', false, 'API'));
|
||||
}
|
||||
// reject larger messages than allowed
|
||||
if (this._maxAllowedSize && envelope.size > this._maxAllowedSize) {
|
||||
setImmediate(() => {
|
||||
done(this._formatError('Message size larger than allowed ' + this._maxAllowedSize, 'EMESSAGE', false, 'MAIL FROM'));
|
||||
});
|
||||
return;
|
||||
}
|
||||
// ensure that callback is only called once
|
||||
// ensure that the callback is only called once. The public callback type has a
|
||||
// required result, the error paths hand over the error alone
|
||||
let returned = false;
|
||||
const callback = function (...args) {
|
||||
const callback = (err, info) => {
|
||||
if (returned) {
|
||||
return;
|
||||
}
|
||||
returned = true;
|
||||
done(...args);
|
||||
done(err, info);
|
||||
};
|
||||
if (!message) {
|
||||
return callback(this._formatError('Empty message', 'EMESSAGE', false, 'API'));
|
||||
}
|
||||
const isDestroyedMessage = this._isDestroyedMessage('send message');
|
||||
if (isDestroyedMessage) {
|
||||
return callback(this._formatError(isDestroyedMessage, 'ECONNECTION', false, 'API'));
|
||||
}
|
||||
// reject larger messages than allowed
|
||||
if (this._maxAllowedSize && envelope.size > this._maxAllowedSize) {
|
||||
setImmediate(() => {
|
||||
callback(this._formatError('Message size larger than allowed ' + this._maxAllowedSize, 'EMESSAGE', false, 'MAIL FROM'));
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (typeof message.on === 'function') {
|
||||
message.on('error', err => callback(this._formatError(err, 'ESTREAM', false, 'API')));
|
||||
}
|
||||
@@ -595,11 +606,13 @@ class SMTPConnection extends EventEmitter {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
info.envelopeTime = envelopeTime - startTime;
|
||||
info.messageTime = Date.now() - envelopeTime;
|
||||
info.messageSize = stream.outByteCount;
|
||||
info.response = str;
|
||||
return callback(null, info);
|
||||
// the envelope info becomes the send result once the timings are on it
|
||||
const result = info;
|
||||
result.envelopeTime = envelopeTime - startTime;
|
||||
result.messageTime = Date.now() - envelopeTime;
|
||||
result.messageSize = stream.outByteCount;
|
||||
result.response = str;
|
||||
return callback(null, result);
|
||||
});
|
||||
if (typeof message.pipe === 'function') {
|
||||
message.pipe(stream);
|
||||
|
||||
Reference in new issue
Block a user