Initial commit
This commit is contained in:
463
node_modules/smtp-server/test/dsn-test.js
generated
vendored
Normal file
463
node_modules/smtp-server/test/dsn-test.js
generated
vendored
Normal file
@@ -0,0 +1,463 @@
|
||||
/* eslint no-unused-expressions:0, prefer-arrow-callback: 0 */
|
||||
|
||||
'use strict';
|
||||
|
||||
const chai = require('chai');
|
||||
const SMTPServer = require('../lib/smtp-server').SMTPServer;
|
||||
const SMTPConnection = require('../lib/smtp-connection').SMTPConnection;
|
||||
|
||||
const expect = chai.expect;
|
||||
|
||||
chai.config.includeStack = true;
|
||||
|
||||
describe('DSN (Delivery Status Notification) Support', function () {
|
||||
this.timeout(10 * 1000); // eslint-disable-line no-invalid-this
|
||||
|
||||
describe('Unit Tests for DSN Parameter Parsing', function () {
|
||||
it('should parse DSN parameters in _parseAddressCommand', function () {
|
||||
let conn = new SMTPConnection(
|
||||
{
|
||||
options: {}
|
||||
},
|
||||
{}
|
||||
);
|
||||
|
||||
// Test MAIL FROM with DSN parameters
|
||||
expect(conn._parseAddressCommand('MAIL FROM', 'MAIL FROM:<sender@example.com> RET=FULL ENVID=test123')).to.deep.equal({
|
||||
address: 'sender@example.com',
|
||||
args: {
|
||||
RET: 'FULL',
|
||||
ENVID: 'test123'
|
||||
}
|
||||
});
|
||||
|
||||
// Test RCPT TO with DSN parameters
|
||||
expect(
|
||||
conn._parseAddressCommand('RCPT TO', 'RCPT TO:<recipient@example.com> NOTIFY=SUCCESS,FAILURE ORCPT=rfc822;original@example.com')
|
||||
).to.deep.equal({
|
||||
address: 'recipient@example.com',
|
||||
args: {
|
||||
NOTIFY: 'SUCCESS,FAILURE',
|
||||
ORCPT: 'rfc822;original@example.com'
|
||||
}
|
||||
});
|
||||
|
||||
// Test mixed parameters
|
||||
expect(conn._parseAddressCommand('MAIL FROM', 'MAIL FROM:<sender@example.com> SIZE=12345 RET=HDRS ENVID=env456')).to.deep.equal({
|
||||
address: 'sender@example.com',
|
||||
args: {
|
||||
SIZE: '12345',
|
||||
RET: 'HDRS',
|
||||
ENVID: 'env456'
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('DSN Session Data Structure', function () {
|
||||
it('should initialize DSN data in session envelope', function () {
|
||||
let conn = new SMTPConnection(
|
||||
{
|
||||
options: {}
|
||||
},
|
||||
{
|
||||
on() {},
|
||||
write() {},
|
||||
end() {}
|
||||
}
|
||||
);
|
||||
|
||||
conn._resetSession();
|
||||
|
||||
expect(conn.session.envelope.dsn).to.exist;
|
||||
expect(conn.session.envelope.dsn.ret).to.be.null;
|
||||
expect(conn.session.envelope.dsn.envid).to.be.null;
|
||||
});
|
||||
});
|
||||
|
||||
describe('EHLO Response', function () {
|
||||
it('should include ENHANCEDSTATUSCODES and DSN in features list', function (done) {
|
||||
let server = new SMTPServer({
|
||||
disabledCommands: ['AUTH'],
|
||||
hideENHANCEDSTATUSCODES: false,
|
||||
hideDSN: false
|
||||
});
|
||||
|
||||
// Mock connection for testing EHLO handler
|
||||
let mockConnection = new SMTPConnection(server, {
|
||||
on() {},
|
||||
write() {},
|
||||
end() {},
|
||||
localAddress: '127.0.0.1',
|
||||
localPort: 25,
|
||||
remoteAddress: '127.0.0.1',
|
||||
remotePort: 12345
|
||||
});
|
||||
|
||||
mockConnection.clientHostname = 'test.example.com';
|
||||
mockConnection.name = 'test-server';
|
||||
|
||||
// Mock the send method to capture the response
|
||||
let sentResponse = null;
|
||||
mockConnection.send = function (code, message) {
|
||||
sentResponse = { code, message };
|
||||
};
|
||||
|
||||
// Test EHLO handler
|
||||
mockConnection.handler_EHLO('EHLO test.example.com', function () {
|
||||
expect(sentResponse).to.exist;
|
||||
expect(sentResponse.code).to.equal(250);
|
||||
expect(sentResponse.message).to.be.an('array');
|
||||
|
||||
// Check if ENHANCEDSTATUSCODES and DSN is in the features
|
||||
const features = sentResponse.message.slice(1); // Skip the greeting
|
||||
expect(features).to.include('ENHANCEDSTATUSCODES');
|
||||
expect(features).to.include('DSN');
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should hide ENHANCEDSTATUSCODES when hideENHANCEDSTATUSCODES is true', function (done) {
|
||||
let server = new SMTPServer({
|
||||
disabledCommands: ['AUTH'],
|
||||
hideENHANCEDSTATUSCODES: true
|
||||
});
|
||||
|
||||
// Mock connection for testing EHLO handler
|
||||
let mockConnection = new SMTPConnection(server, {
|
||||
on() {},
|
||||
write() {},
|
||||
end() {},
|
||||
localAddress: '127.0.0.1',
|
||||
localPort: 25,
|
||||
remoteAddress: '127.0.0.1',
|
||||
remotePort: 12345
|
||||
});
|
||||
|
||||
mockConnection.clientHostname = 'test.example.com';
|
||||
mockConnection.name = 'test-server';
|
||||
|
||||
// Mock the send method to capture the response
|
||||
let sentResponse = null;
|
||||
mockConnection.send = function (code, message) {
|
||||
sentResponse = { code, message };
|
||||
};
|
||||
|
||||
// Test EHLO handler
|
||||
mockConnection.handler_EHLO('EHLO test.example.com', function () {
|
||||
expect(sentResponse).to.exist;
|
||||
expect(sentResponse.code).to.equal(250);
|
||||
expect(sentResponse.message).to.be.an('array');
|
||||
|
||||
// Check if ENHANCEDSTATUSCODES is NOT in the features
|
||||
const features = sentResponse.message.slice(1); // Skip the greeting
|
||||
expect(features).to.not.include('ENHANCEDSTATUSCODES');
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should hide DSN when hideDSN is true', function (done) {
|
||||
let server = new SMTPServer({
|
||||
disabledCommands: ['AUTH'],
|
||||
hideDSN: true
|
||||
});
|
||||
|
||||
// Mock connection for testing EHLO handler
|
||||
let mockConnection = new SMTPConnection(server, {
|
||||
on() {},
|
||||
write() {},
|
||||
end() {},
|
||||
localAddress: '127.0.0.1',
|
||||
localPort: 25,
|
||||
remoteAddress: '127.0.0.1',
|
||||
remotePort: 12345
|
||||
});
|
||||
|
||||
mockConnection.clientHostname = 'test.example.com';
|
||||
mockConnection.name = 'test-server';
|
||||
|
||||
// Mock the send method to capture the response
|
||||
let sentResponse = null;
|
||||
mockConnection.send = function (code, message) {
|
||||
sentResponse = { code, message };
|
||||
};
|
||||
|
||||
// Test EHLO handler
|
||||
mockConnection.handler_EHLO('EHLO test.example.com', function () {
|
||||
expect(sentResponse).to.exist;
|
||||
expect(sentResponse.code).to.equal(250);
|
||||
expect(sentResponse.message).to.be.an('array');
|
||||
|
||||
// Check if DSN is NOT in the features
|
||||
const features = sentResponse.message.slice(1); // Skip the greeting
|
||||
expect(features).to.not.include('DSN');
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('MAIL FROM DSN Parameter Validation', function () {
|
||||
it('should accept valid RET=FULL parameter', function (done) {
|
||||
let server = new SMTPServer({
|
||||
hideDSN: false,
|
||||
onMailFrom(address, session, callback) {
|
||||
expect(session.envelope.dsn.ret).to.equal('FULL');
|
||||
expect(address.args.RET).to.equal('FULL');
|
||||
callback();
|
||||
}
|
||||
});
|
||||
|
||||
let mockConnection = new SMTPConnection(server, {
|
||||
on() {},
|
||||
write() {},
|
||||
end() {},
|
||||
localAddress: '127.0.0.1',
|
||||
localPort: 25,
|
||||
remoteAddress: '127.0.0.1',
|
||||
remotePort: 12345
|
||||
});
|
||||
|
||||
mockConnection._resetSession();
|
||||
mockConnection.openingCommand = 'EHLO';
|
||||
|
||||
let sentResponse = null;
|
||||
mockConnection.send = function (code, message) {
|
||||
sentResponse = { code, message };
|
||||
};
|
||||
|
||||
mockConnection.handler_MAIL('MAIL FROM:<test@example.com> RET=FULL', function () {
|
||||
expect(sentResponse).to.exist;
|
||||
expect(sentResponse.code).to.equal(250);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should reject invalid RET parameter', function (done) {
|
||||
let server = new SMTPServer({
|
||||
hideDSN: false,
|
||||
onMailFrom(address, session, callback) {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
|
||||
let mockConnection = new SMTPConnection(server, {
|
||||
on() {},
|
||||
write() {},
|
||||
end() {},
|
||||
localAddress: '127.0.0.1',
|
||||
localPort: 25,
|
||||
remoteAddress: '127.0.0.1',
|
||||
remotePort: 12345
|
||||
});
|
||||
|
||||
mockConnection._resetSession();
|
||||
mockConnection.openingCommand = 'EHLO';
|
||||
|
||||
let sentResponse = null;
|
||||
mockConnection.send = function (code, message) {
|
||||
sentResponse = { code, message };
|
||||
};
|
||||
|
||||
mockConnection.handler_MAIL('MAIL FROM:<test@example.com> RET=INVALID', function () {
|
||||
expect(sentResponse).to.exist;
|
||||
expect(sentResponse.code).to.equal(501);
|
||||
expect(sentResponse.message).to.include('Invalid RET parameter');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should accept ENVID parameter', function (done) {
|
||||
let server = new SMTPServer({
|
||||
hideDSN: false,
|
||||
onMailFrom(address, session, callback) {
|
||||
expect(session.envelope.dsn.envid).to.equal('test-envelope-123');
|
||||
expect(address.args.ENVID).to.equal('test-envelope-123');
|
||||
callback();
|
||||
}
|
||||
});
|
||||
|
||||
let mockConnection = new SMTPConnection(server, {
|
||||
on() {},
|
||||
write() {},
|
||||
end() {},
|
||||
localAddress: '127.0.0.1',
|
||||
localPort: 25,
|
||||
remoteAddress: '127.0.0.1',
|
||||
remotePort: 12345
|
||||
});
|
||||
|
||||
mockConnection._resetSession();
|
||||
mockConnection.openingCommand = 'EHLO';
|
||||
|
||||
let sentResponse = null;
|
||||
mockConnection.send = function (code, message) {
|
||||
sentResponse = { code, message };
|
||||
};
|
||||
|
||||
mockConnection.handler_MAIL('MAIL FROM:<test@example.com> ENVID=test-envelope-123', function () {
|
||||
expect(sentResponse).to.exist;
|
||||
expect(sentResponse.code).to.equal(250);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('RCPT TO DSN Parameter Validation', function () {
|
||||
it('should accept valid NOTIFY=SUCCESS parameter', function (done) {
|
||||
let server = new SMTPServer({
|
||||
hideDSN: false,
|
||||
onMailFrom(address, session, callback) {
|
||||
callback();
|
||||
},
|
||||
onRcptTo(address, session, callback) {
|
||||
expect(address.dsn.notify).to.deep.equal(['SUCCESS']);
|
||||
expect(address.args.NOTIFY).to.equal('SUCCESS');
|
||||
callback();
|
||||
}
|
||||
});
|
||||
|
||||
let mockConnection = new SMTPConnection(server, {
|
||||
on() {},
|
||||
write() {},
|
||||
end() {},
|
||||
localAddress: '127.0.0.1',
|
||||
localPort: 25,
|
||||
remoteAddress: '127.0.0.1',
|
||||
remotePort: 12345
|
||||
});
|
||||
|
||||
mockConnection._resetSession();
|
||||
mockConnection.openingCommand = 'EHLO';
|
||||
mockConnection.session.envelope.mailFrom = { address: 'test@example.com' };
|
||||
|
||||
let sentResponse = null;
|
||||
mockConnection.send = function (code, message) {
|
||||
sentResponse = { code, message };
|
||||
};
|
||||
|
||||
mockConnection.handler_RCPT('RCPT TO:<recipient@example.com> NOTIFY=SUCCESS', function () {
|
||||
expect(sentResponse).to.exist;
|
||||
expect(sentResponse.code).to.equal(250);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should reject invalid NOTIFY parameter', function (done) {
|
||||
let server = new SMTPServer({
|
||||
hideDSN: false,
|
||||
onMailFrom(address, session, callback) {
|
||||
callback();
|
||||
},
|
||||
onRcptTo(address, session, callback) {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
|
||||
let mockConnection = new SMTPConnection(server, {
|
||||
on() {},
|
||||
write() {},
|
||||
end() {},
|
||||
localAddress: '127.0.0.1',
|
||||
localPort: 25,
|
||||
remoteAddress: '127.0.0.1',
|
||||
remotePort: 12345
|
||||
});
|
||||
|
||||
mockConnection._resetSession();
|
||||
mockConnection.openingCommand = 'EHLO';
|
||||
mockConnection.session.envelope.mailFrom = { address: 'test@example.com' };
|
||||
|
||||
let sentResponse = null;
|
||||
mockConnection.send = function (code, message) {
|
||||
sentResponse = { code, message };
|
||||
};
|
||||
|
||||
mockConnection.handler_RCPT('RCPT TO:<recipient@example.com> NOTIFY=INVALID', function () {
|
||||
expect(sentResponse).to.exist;
|
||||
expect(sentResponse.code).to.equal(501);
|
||||
expect(sentResponse.message).to.include('NOTIFY parameter must be NEVER, SUCCESS, FAILURE, or DELAY');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should reject NOTIFY=NEVER combined with other values', function (done) {
|
||||
let server = new SMTPServer({
|
||||
hideDSN: false,
|
||||
onMailFrom(address, session, callback) {
|
||||
callback();
|
||||
},
|
||||
onRcptTo(address, session, callback) {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
|
||||
let mockConnection = new SMTPConnection(server, {
|
||||
on() {},
|
||||
write() {},
|
||||
end() {},
|
||||
localAddress: '127.0.0.1',
|
||||
localPort: 25,
|
||||
remoteAddress: '127.0.0.1',
|
||||
remotePort: 12345
|
||||
});
|
||||
|
||||
mockConnection._resetSession();
|
||||
mockConnection.openingCommand = 'EHLO';
|
||||
mockConnection.session.envelope.mailFrom = { address: 'test@example.com' };
|
||||
|
||||
let sentResponse = null;
|
||||
mockConnection.send = function (code, message) {
|
||||
sentResponse = { code, message };
|
||||
};
|
||||
|
||||
mockConnection.handler_RCPT('RCPT TO:<recipient@example.com> NOTIFY=NEVER,SUCCESS', function () {
|
||||
expect(sentResponse).to.exist;
|
||||
expect(sentResponse.code).to.equal(501);
|
||||
expect(sentResponse.message).to.include('NOTIFY=NEVER cannot be combined with other values');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should accept ORCPT parameter', function (done) {
|
||||
let server = new SMTPServer({
|
||||
hideDSN: false,
|
||||
onMailFrom(address, session, callback) {
|
||||
callback();
|
||||
},
|
||||
onRcptTo(address, session, callback) {
|
||||
expect(address.dsn.orcpt).to.equal('rfc822;original@example.com');
|
||||
expect(address.args.ORCPT).to.equal('rfc822;original@example.com');
|
||||
callback();
|
||||
}
|
||||
});
|
||||
|
||||
let mockConnection = new SMTPConnection(server, {
|
||||
on() {},
|
||||
write() {},
|
||||
end() {},
|
||||
localAddress: '127.0.0.1',
|
||||
localPort: 25,
|
||||
remoteAddress: '127.0.0.1',
|
||||
remotePort: 12345
|
||||
});
|
||||
|
||||
mockConnection._resetSession();
|
||||
mockConnection.openingCommand = 'EHLO';
|
||||
mockConnection.session.envelope.mailFrom = { address: 'test@example.com' };
|
||||
|
||||
let sentResponse = null;
|
||||
mockConnection.send = function (code, message) {
|
||||
sentResponse = { code, message };
|
||||
};
|
||||
|
||||
mockConnection.handler_RCPT('RCPT TO:<recipient@example.com> ORCPT=rfc822;original@example.com', function () {
|
||||
expect(sentResponse).to.exist;
|
||||
expect(sentResponse.code).to.equal(250);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
425
node_modules/smtp-server/test/mail-parameters-test.js
generated
vendored
Normal file
425
node_modules/smtp-server/test/mail-parameters-test.js
generated
vendored
Normal file
@@ -0,0 +1,425 @@
|
||||
/* eslint no-unused-expressions:0 */
|
||||
|
||||
'use strict';
|
||||
|
||||
const chai = require('chai');
|
||||
const SMTPServer = require('../lib/smtp-server').SMTPServer;
|
||||
const SMTPConnection = require('../lib/smtp-connection').SMTPConnection;
|
||||
|
||||
const expect = chai.expect;
|
||||
|
||||
chai.config.includeStack = true;
|
||||
|
||||
describe('MAIL FROM Parameters (BODY, SMTPUTF8, REQUIRETLS)', function () {
|
||||
this.timeout(10 * 1000); // eslint-disable-line no-invalid-this
|
||||
|
||||
describe('Unit Tests for Parameter Parsing', function () {
|
||||
it('should parse BODY parameter in _parseAddressCommand', () => {
|
||||
let conn = new SMTPConnection(
|
||||
{
|
||||
options: {}
|
||||
},
|
||||
{}
|
||||
);
|
||||
|
||||
// Test BODY=8BITMIME
|
||||
expect(conn._parseAddressCommand('MAIL FROM', 'MAIL FROM:<sender@example.com> BODY=8BITMIME')).to.deep.equal({
|
||||
address: 'sender@example.com',
|
||||
args: {
|
||||
BODY: '8BITMIME'
|
||||
}
|
||||
});
|
||||
|
||||
// Test BODY=7BIT
|
||||
expect(conn._parseAddressCommand('MAIL FROM', 'MAIL FROM:<sender@example.com> BODY=7BIT')).to.deep.equal({
|
||||
address: 'sender@example.com',
|
||||
args: {
|
||||
BODY: '7BIT'
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should parse SMTPUTF8 parameter in _parseAddressCommand', () => {
|
||||
let conn = new SMTPConnection(
|
||||
{
|
||||
options: {}
|
||||
},
|
||||
{}
|
||||
);
|
||||
|
||||
// Test SMTPUTF8 flag
|
||||
expect(conn._parseAddressCommand('MAIL FROM', 'MAIL FROM:<sender@example.com> SMTPUTF8')).to.deep.equal({
|
||||
address: 'sender@example.com',
|
||||
args: {
|
||||
SMTPUTF8: true
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should parse REQUIRETLS parameter in _parseAddressCommand', () => {
|
||||
let conn = new SMTPConnection(
|
||||
{
|
||||
options: {}
|
||||
},
|
||||
{}
|
||||
);
|
||||
|
||||
// Test REQUIRETLS flag
|
||||
expect(conn._parseAddressCommand('MAIL FROM', 'MAIL FROM:<sender@example.com> REQUIRETLS')).to.deep.equal({
|
||||
address: 'sender@example.com',
|
||||
args: {
|
||||
REQUIRETLS: true
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should parse combined parameters', () => {
|
||||
let conn = new SMTPConnection(
|
||||
{
|
||||
options: {}
|
||||
},
|
||||
{}
|
||||
);
|
||||
|
||||
// Test all three parameters together
|
||||
expect(conn._parseAddressCommand('MAIL FROM', 'MAIL FROM:<sender@example.com> BODY=8BITMIME SMTPUTF8 REQUIRETLS')).to.deep.equal({
|
||||
address: 'sender@example.com',
|
||||
args: {
|
||||
BODY: '8BITMIME',
|
||||
SMTPUTF8: true,
|
||||
REQUIRETLS: true
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Session Data Structure', function () {
|
||||
it('should initialize parameter fields in session envelope', () => {
|
||||
let conn = new SMTPConnection(
|
||||
{
|
||||
options: {}
|
||||
},
|
||||
{
|
||||
on() {},
|
||||
write() {},
|
||||
end() {}
|
||||
}
|
||||
);
|
||||
|
||||
conn._resetSession();
|
||||
|
||||
expect(conn.session.envelope.bodyType).to.equal('7bit');
|
||||
expect(conn.session.envelope.smtpUtf8).to.equal(false);
|
||||
expect(conn.session.envelope.requireTLS).to.equal(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('EHLO Response', function () {
|
||||
it('should include 8BITMIME and SMTPUTF8 in features list', done => {
|
||||
let server = new SMTPServer({
|
||||
disabledCommands: ['AUTH']
|
||||
});
|
||||
|
||||
let mockConnection = new SMTPConnection(server, {
|
||||
on() {},
|
||||
write() {},
|
||||
end() {},
|
||||
localAddress: '127.0.0.1',
|
||||
localPort: 25,
|
||||
remoteAddress: '127.0.0.1',
|
||||
remotePort: 12345
|
||||
});
|
||||
|
||||
mockConnection.clientHostname = 'test.example.com';
|
||||
mockConnection.name = 'test-server';
|
||||
|
||||
let sentResponse = null;
|
||||
mockConnection.send = (code, message) => {
|
||||
sentResponse = { code, message };
|
||||
};
|
||||
|
||||
mockConnection.handler_EHLO('EHLO test.example.com', () => {
|
||||
expect(sentResponse).to.exist;
|
||||
expect(sentResponse.code).to.equal(250);
|
||||
expect(sentResponse.message).to.be.an('array');
|
||||
const features = sentResponse.message.slice(1);
|
||||
expect(features).to.include('8BITMIME');
|
||||
expect(features).to.include('SMTPUTF8');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should include REQUIRETLS when secure and not hidden', done => {
|
||||
let server = new SMTPServer({
|
||||
disabledCommands: ['AUTH'],
|
||||
hideREQUIRETLS: false
|
||||
});
|
||||
|
||||
let mockConnection = new SMTPConnection(server, {
|
||||
on() {},
|
||||
write() {},
|
||||
end() {},
|
||||
localAddress: '127.0.0.1',
|
||||
localPort: 25,
|
||||
remoteAddress: '127.0.0.1',
|
||||
remotePort: 12345
|
||||
});
|
||||
|
||||
mockConnection.clientHostname = 'test.example.com';
|
||||
mockConnection.name = 'test-server';
|
||||
mockConnection.secure = true; // Simulate TLS connection
|
||||
|
||||
let sentResponse = null;
|
||||
mockConnection.send = (code, message) => {
|
||||
sentResponse = { code, message };
|
||||
};
|
||||
|
||||
mockConnection.handler_EHLO('EHLO test.example.com', () => {
|
||||
expect(sentResponse).to.exist;
|
||||
expect(sentResponse.code).to.equal(250);
|
||||
expect(sentResponse.message).to.be.an('array');
|
||||
const features = sentResponse.message.slice(1);
|
||||
expect(features).to.include('REQUIRETLS');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should hide REQUIRETLS by default', done => {
|
||||
let server = new SMTPServer({
|
||||
disabledCommands: ['AUTH']
|
||||
});
|
||||
|
||||
let mockConnection = new SMTPConnection(server, {
|
||||
on() {},
|
||||
write() {},
|
||||
end() {},
|
||||
localAddress: '127.0.0.1',
|
||||
localPort: 25,
|
||||
remoteAddress: '127.0.0.1',
|
||||
remotePort: 12345
|
||||
});
|
||||
|
||||
mockConnection.clientHostname = 'test.example.com';
|
||||
mockConnection.name = 'test-server';
|
||||
mockConnection.secure = true; // Simulate TLS connection
|
||||
|
||||
let sentResponse = null;
|
||||
mockConnection.send = (code, message) => {
|
||||
sentResponse = { code, message };
|
||||
};
|
||||
|
||||
mockConnection.handler_EHLO('EHLO test.example.com', () => {
|
||||
expect(sentResponse).to.exist;
|
||||
expect(sentResponse.code).to.equal(250);
|
||||
expect(sentResponse.message).to.be.an('array');
|
||||
const features = sentResponse.message.slice(1);
|
||||
expect(features).to.not.include('REQUIRETLS');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('MAIL FROM Parameter Validation', function () {
|
||||
it('should accept valid BODY=8BITMIME parameter', done => {
|
||||
let server = new SMTPServer({
|
||||
disabledCommands: ['AUTH'],
|
||||
authOptional: true,
|
||||
onMailFrom: (address, session, callback) => {
|
||||
expect(session.envelope.bodyType).to.equal('8bitmime');
|
||||
callback();
|
||||
}
|
||||
});
|
||||
|
||||
let mockConnection = new SMTPConnection(server, {
|
||||
on() {},
|
||||
write() {},
|
||||
end() {},
|
||||
localAddress: '127.0.0.1',
|
||||
localPort: 25,
|
||||
remoteAddress: '127.0.0.1',
|
||||
remotePort: 12345
|
||||
});
|
||||
|
||||
mockConnection._resetSession();
|
||||
mockConnection.send = code => {
|
||||
expect(code).to.equal(250);
|
||||
done();
|
||||
};
|
||||
|
||||
mockConnection.handler_MAIL('MAIL FROM:<sender@example.com> BODY=8BITMIME', () => {});
|
||||
});
|
||||
|
||||
it('should reject invalid BODY parameter', done => {
|
||||
let server = new SMTPServer({
|
||||
disabledCommands: ['AUTH'],
|
||||
authOptional: true
|
||||
});
|
||||
|
||||
let mockConnection = new SMTPConnection(server, {
|
||||
on() {},
|
||||
write() {},
|
||||
end() {},
|
||||
localAddress: '127.0.0.1',
|
||||
localPort: 25,
|
||||
remoteAddress: '127.0.0.1',
|
||||
remotePort: 12345
|
||||
});
|
||||
|
||||
mockConnection._resetSession();
|
||||
mockConnection.send = (code, message) => {
|
||||
expect(code).to.equal(501);
|
||||
expect(message).to.include('Invalid BODY parameter');
|
||||
done();
|
||||
};
|
||||
|
||||
mockConnection.handler_MAIL('MAIL FROM:<sender@example.com> BODY=INVALID', () => {});
|
||||
});
|
||||
|
||||
it('should accept SMTPUTF8 parameter', done => {
|
||||
let server = new SMTPServer({
|
||||
disabledCommands: ['AUTH'],
|
||||
authOptional: true,
|
||||
onMailFrom: (address, session, callback) => {
|
||||
expect(session.envelope.smtpUtf8).to.equal(true);
|
||||
callback();
|
||||
}
|
||||
});
|
||||
|
||||
let mockConnection = new SMTPConnection(server, {
|
||||
on() {},
|
||||
write() {},
|
||||
end() {},
|
||||
localAddress: '127.0.0.1',
|
||||
localPort: 25,
|
||||
remoteAddress: '127.0.0.1',
|
||||
remotePort: 12345
|
||||
});
|
||||
|
||||
mockConnection._resetSession();
|
||||
mockConnection.send = code => {
|
||||
expect(code).to.equal(250);
|
||||
done();
|
||||
};
|
||||
|
||||
mockConnection.handler_MAIL('MAIL FROM:<sender@example.com> SMTPUTF8', () => {});
|
||||
});
|
||||
|
||||
it('should reject SMTPUTF8 with value', done => {
|
||||
let server = new SMTPServer({
|
||||
disabledCommands: ['AUTH'],
|
||||
authOptional: true
|
||||
});
|
||||
|
||||
let mockConnection = new SMTPConnection(server, {
|
||||
on() {},
|
||||
write() {},
|
||||
end() {},
|
||||
localAddress: '127.0.0.1',
|
||||
localPort: 25,
|
||||
remoteAddress: '127.0.0.1',
|
||||
remotePort: 12345
|
||||
});
|
||||
|
||||
mockConnection._resetSession();
|
||||
mockConnection.send = (code, message) => {
|
||||
expect(code).to.equal(501);
|
||||
expect(message).to.include('does not accept a value');
|
||||
done();
|
||||
};
|
||||
|
||||
mockConnection.handler_MAIL('MAIL FROM:<sender@example.com> SMTPUTF8=YES', () => {});
|
||||
});
|
||||
|
||||
it('should accept REQUIRETLS parameter over TLS', done => {
|
||||
let server = new SMTPServer({
|
||||
disabledCommands: ['AUTH'],
|
||||
authOptional: true,
|
||||
hideREQUIRETLS: false,
|
||||
onMailFrom: (address, session, callback) => {
|
||||
expect(session.envelope.requireTLS).to.equal(true);
|
||||
callback();
|
||||
}
|
||||
});
|
||||
|
||||
let mockConnection = new SMTPConnection(server, {
|
||||
on() {},
|
||||
write() {},
|
||||
end() {},
|
||||
localAddress: '127.0.0.1',
|
||||
localPort: 25,
|
||||
remoteAddress: '127.0.0.1',
|
||||
remotePort: 12345
|
||||
});
|
||||
|
||||
mockConnection._resetSession();
|
||||
mockConnection.secure = true; // Simulate TLS connection
|
||||
mockConnection.send = code => {
|
||||
expect(code).to.equal(250);
|
||||
done();
|
||||
};
|
||||
|
||||
mockConnection.handler_MAIL('MAIL FROM:<sender@example.com> REQUIRETLS', () => {});
|
||||
});
|
||||
|
||||
it('should reject REQUIRETLS without TLS', done => {
|
||||
let server = new SMTPServer({
|
||||
disabledCommands: ['AUTH'],
|
||||
authOptional: true,
|
||||
hideREQUIRETLS: false
|
||||
});
|
||||
|
||||
let mockConnection = new SMTPConnection(server, {
|
||||
on() {},
|
||||
write() {},
|
||||
end() {},
|
||||
localAddress: '127.0.0.1',
|
||||
localPort: 25,
|
||||
remoteAddress: '127.0.0.1',
|
||||
remotePort: 12345
|
||||
});
|
||||
|
||||
mockConnection._resetSession();
|
||||
mockConnection.secure = false; // Not secure
|
||||
mockConnection.send = (code, message) => {
|
||||
expect(code).to.equal(530);
|
||||
expect(message).to.include('not permitted on non-TLS');
|
||||
done();
|
||||
};
|
||||
|
||||
mockConnection.handler_MAIL('MAIL FROM:<sender@example.com> REQUIRETLS', () => {});
|
||||
});
|
||||
|
||||
it('should accept combined parameters', done => {
|
||||
let server = new SMTPServer({
|
||||
disabledCommands: ['AUTH'],
|
||||
authOptional: true,
|
||||
hideREQUIRETLS: false,
|
||||
onMailFrom: (address, session, callback) => {
|
||||
expect(session.envelope.bodyType).to.equal('8bitmime');
|
||||
expect(session.envelope.smtpUtf8).to.equal(true);
|
||||
expect(session.envelope.requireTLS).to.equal(true);
|
||||
callback();
|
||||
}
|
||||
});
|
||||
|
||||
let mockConnection = new SMTPConnection(server, {
|
||||
on() {},
|
||||
write() {},
|
||||
end() {},
|
||||
localAddress: '127.0.0.1',
|
||||
localPort: 25,
|
||||
remoteAddress: '127.0.0.1',
|
||||
remotePort: 12345
|
||||
});
|
||||
|
||||
mockConnection._resetSession();
|
||||
mockConnection.secure = true;
|
||||
mockConnection.send = code => {
|
||||
expect(code).to.equal(250);
|
||||
done();
|
||||
};
|
||||
|
||||
mockConnection.handler_MAIL('MAIL FROM:<sender@example.com> BODY=8BITMIME SMTPUTF8 REQUIRETLS', () => {});
|
||||
});
|
||||
});
|
||||
});
|
||||
1880
node_modules/smtp-server/test/smtp-connection-test.js
generated
vendored
Normal file
1880
node_modules/smtp-server/test/smtp-connection-test.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
60
node_modules/smtp-server/test/smtp-stream-test.js
generated
vendored
Normal file
60
node_modules/smtp-server/test/smtp-stream-test.js
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
/* eslint no-unused-expressions:0, prefer-arrow-callback: 0 */
|
||||
|
||||
'use strict';
|
||||
|
||||
const chai = require('chai');
|
||||
const SMTPStream = require('../lib/smtp-stream').SMTPStream;
|
||||
const expect = chai.expect;
|
||||
|
||||
chai.config.includeStack = true;
|
||||
|
||||
describe('SMTPStream', function () {
|
||||
it('should emit commands', function (done) {
|
||||
let stream = new SMTPStream();
|
||||
|
||||
let expecting = [Buffer.from([0x43, 0x4d, 0x44, 0x31]), Buffer.from([0x43, 0x4d, 0x44, 0x32]), Buffer.from([0x43, 0x4d, 0x44, 0x33])];
|
||||
|
||||
stream.oncommand = function (cmd, cb) {
|
||||
expect(cmd).to.deep.equal(expecting.shift());
|
||||
if (cb) {
|
||||
return cb();
|
||||
} else {
|
||||
return done();
|
||||
}
|
||||
};
|
||||
|
||||
stream.end('CMD1\r\nCMD2\r\nCMD3');
|
||||
});
|
||||
|
||||
it('should start data stream', function (done) {
|
||||
let stream = new SMTPStream();
|
||||
|
||||
let expecting = ['DATA', 'QUIT'];
|
||||
|
||||
stream.oncommand = function (cmd, cb) {
|
||||
cmd = cmd.toString();
|
||||
expect(cmd).to.deep.equal(expecting.shift());
|
||||
|
||||
let datastream;
|
||||
let output = '';
|
||||
if (cmd === 'DATA') {
|
||||
datastream = stream.startDataMode();
|
||||
datastream.on('data', function (chunk) {
|
||||
output += chunk.toString();
|
||||
});
|
||||
datastream.on('end', function () {
|
||||
expect(output).to.equal('test1\r\n.test2\r\n.test3\r\n');
|
||||
stream.continue();
|
||||
});
|
||||
}
|
||||
|
||||
if (cb) {
|
||||
return cb();
|
||||
} else {
|
||||
return done();
|
||||
}
|
||||
};
|
||||
|
||||
stream.end('DATA\r\ntest1\r\n..test2\r\n.test3\r\n.\r\nQUIT');
|
||||
});
|
||||
});
|
||||
46
node_modules/smtp-server/test/test-resolver.js
generated
vendored
Normal file
46
node_modules/smtp-server/test/test-resolver.js
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
// Test script for issue #177 fix
|
||||
'use strict';
|
||||
|
||||
const SMTPServer = require('../lib/smtp-server').SMTPServer;
|
||||
|
||||
// Create a custom resolver
|
||||
const customResolver = {
|
||||
reverse: (ip, callback) => {
|
||||
console.log('Custom resolver called with IP:', ip);
|
||||
// Return a custom hostname for testing
|
||||
callback(null, ['custom-resolved-hostname.example.com']);
|
||||
}
|
||||
};
|
||||
|
||||
// Create SMTP server with custom resolver
|
||||
const server = new SMTPServer({
|
||||
logger: {
|
||||
info: console.info,
|
||||
debug: console.debug,
|
||||
error: console.error
|
||||
},
|
||||
resolver: customResolver,
|
||||
onConnect: (session, callback) => {
|
||||
console.log('Client connected with session:', session.id);
|
||||
console.log('Client hostname resolved to:', session.clientHostname);
|
||||
callback();
|
||||
}
|
||||
});
|
||||
|
||||
// Start server on a random port
|
||||
server.listen(0, '127.0.0.1', () => {
|
||||
const address = server.server.address();
|
||||
console.log(`SMTP Server listening on [${address.address}]:${address.port}`);
|
||||
console.log('Test successful - custom resolver is being used');
|
||||
|
||||
// Close the server after a short delay
|
||||
setTimeout(() => {
|
||||
console.log('Closing server...');
|
||||
server.close();
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
// Handle errors
|
||||
server.on('error', err => {
|
||||
console.error('SMTP Server error:', err);
|
||||
});
|
||||
74
node_modules/smtp-server/test/test-server-closing.js
generated
vendored
Normal file
74
node_modules/smtp-server/test/test-server-closing.js
generated
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
// Test script for issue #181 fix
|
||||
'use strict';
|
||||
|
||||
const SMTPServer = require('../lib/smtp-server').SMTPServer;
|
||||
const net = require('net');
|
||||
|
||||
// Create SMTP server
|
||||
const server = new SMTPServer({
|
||||
logger: {
|
||||
info: console.info,
|
||||
debug: console.debug,
|
||||
error: console.error
|
||||
},
|
||||
onConnect: (session, callback) => {
|
||||
console.log('Client connected with session:', session.id);
|
||||
callback();
|
||||
}
|
||||
});
|
||||
|
||||
// Start server on a random port
|
||||
server.listen(0, '127.0.0.1', () => {
|
||||
const address = server.server.address();
|
||||
console.log(`SMTP Server listening on [${address.address}]:${address.port}`);
|
||||
|
||||
// Test the server shutdown behavior
|
||||
console.log('Starting server shutdown test...');
|
||||
|
||||
// Connect a client
|
||||
const client = net.createConnection(address.port, address.address, () => {
|
||||
console.log('Client connected to server');
|
||||
|
||||
// Set up data handler
|
||||
client.on('data', data => {
|
||||
const response = data.toString();
|
||||
console.log('Server response:', response);
|
||||
|
||||
// After receiving the greeting, initiate server shutdown and try to send a command
|
||||
if (response.startsWith('220')) {
|
||||
console.log('Initiating server shutdown...');
|
||||
|
||||
// Trigger server shutdown
|
||||
server.close(() => {
|
||||
console.log('Server shutdown complete');
|
||||
});
|
||||
|
||||
// Wait a moment and then try to send a command
|
||||
setTimeout(() => {
|
||||
console.log('Sending HELO command during shutdown...');
|
||||
client.write('HELO example.com\r\n');
|
||||
|
||||
// Wait for response and then close client
|
||||
setTimeout(() => {
|
||||
console.log('Test complete - client disconnecting');
|
||||
client.end();
|
||||
}, 500);
|
||||
}, 100);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
client.on('close', () => {
|
||||
console.log('Client connection closed');
|
||||
process.exit(0);
|
||||
});
|
||||
|
||||
client.on('error', err => {
|
||||
console.error('Client error:', err.message);
|
||||
});
|
||||
});
|
||||
|
||||
// Handle errors
|
||||
server.on('error', err => {
|
||||
console.error('SMTP Server error:', err);
|
||||
});
|
||||
Reference in New Issue
Block a user