Socket
Socket
Sign inDemoInstall

smtp-server

Package Overview
Dependencies
0
Maintainers
1
Versions
65
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 1.6.0 to 1.7.0

6

CHANGELOG.md
# Changelog
## v1.7.0 2015-10-27
* Added support for XCLIENT with `useXClient` option
* Fixed an issue with an empty space after EHLO (67acb1534 by AtlasDev)
* Added dummy handlers for KILL, WIZ, SHELL
## v1.6.0 2015-09-29

@@ -4,0 +10,0 @@

5

examples/server.js

@@ -32,2 +32,5 @@ 'use strict';

// allow overriding connection properties. Only makes sense behind proxy
useXClient: true,
// Setup authentication

@@ -104,2 +107,2 @@ // Allow only users with username 'testuser' and password 'testpass'

// start listening
server.listen(SERVER_PORT, SERVER_HOST);
server.listen(SERVER_PORT, SERVER_HOST);

148

lib/smtp-connection.js

@@ -6,2 +6,3 @@ 'use strict';

var tls = require('tls');
var net = require('net');
var sasl = require('./sasl');

@@ -80,2 +81,5 @@ var crypto = require('crypto');

// data passed from XCLIENT command
this._xclient = new Map();
// increment connection count

@@ -434,3 +438,3 @@ this._closing = false;

SMTPConnection.prototype.handler_EHLO = function(command, callback) {
var parts = command.toString().split(/\s+/);
var parts = command.toString().trim().split(/\s+/);
var hostname = parts[1] || '';

@@ -459,2 +463,6 @@

if (!this._xclient.has('ADDR') && this._server.options.useXClient && this._isSupported('XCLIENT')) {
features.push('XCLIENT NAME ADDR PORT PROTO HELO LOGIN');
}
this._startSession(); // EHLO is effectively the same as RSET

@@ -470,3 +478,3 @@ this.send(250, ['OK: Nice to meet you ' + this.clientHostname].concat(features || []));

SMTPConnection.prototype.handler_HELO = function(command, callback) {
var parts = command.toString().split(/\s+/);
var parts = command.toString().trim().split(/\s+/);
var hostname = parts[1] || '';

@@ -531,2 +539,91 @@

/**
* Overrides connection info
*/
SMTPConnection.prototype.handler_XCLIENT = function(command, callback) {
// check if user is authorized to perform this command
if (this._xclient.has('ADDR') || !this._server.options.useXClient) {
this.send(550, 'Error: Not allowed');
return callback();
}
// not allowed to change properties if already processing mail
if (this.session.envelope.mailFrom) {
this.send(503, 'Error: Mail transaction in progress');
return callback();
}
var allowedKeys = ['NAME', 'ADDR', 'PORT', 'PROTO', 'HELO', 'LOGIN'];
var parts = command.toString().trim().split(/\s+/);
var key, value;
var data = new Map();
parts.shift(); // remove XCLIENT prefix
if (!parts.length) {
this.send(501, 'Error: Bad command parameter syntax');
return callback();
}
// parse and validate arguments
for (var i = 0, len = parts.length; i < len; i++) {
value = parts[i].split('=');
key = value.shift();
if (value.length !== 1 || allowedKeys.indexOf(key.toUpperCase()) < 0) {
this.send(501, 'Error: Bad command parameter syntax');
return callback();
}
key = key.toUpperCase();
value = value[0];
if (['[UNAVAILABLE]', '[TEMPUNAVAIL]'].indexOf(value.toUpperCase()) >= 0) {
value = false;
}
data.set(key, value);
}
// override connection properties
data.forEach(function(value, key) {
switch (key) {
case 'LOGIN':
if (!value) {
if (this.session.user) {
this._server.logger.info('[%s] User deauthenticated using %s', this._id, 'XCLIENT');
}
} else {
this._server.logger.info('[%s] %s authenticated using %s', this._id, value, 'XCLIENT');
this.session.user = {
username: value
};
}
break;
case 'ADDR':
if (value) {
if (!net.isIP) {
this.send(501, 'Error: Bad command parameter syntax. Invalid address');
return callback();
}
this._server.logger.info('[%s] XCLIENT from %s through %s', this._id, value, this.remoteAddress);
this.remoteAddress = value.toLowerCase();
this.hostNameAppearsAs = false; // reset client provided hostname, require HELO/EHLO
}
break;
case 'NAME':
this._server.logger.info('[%s] XCLIENT hostname resolved as "%s"', this._id, value || '');
this.clientHostname = value.toLowerCase();
break;
default:
// other values are not relevant
}
this._xclient.set(key, value);
}.bind(this));
// Use [ADDR] if NAME was empty
if (this.remoteAddress && !this.clientHostname) {
this.clientHostname = '[' + this.remoteAddress + ']';
}
// success
this.send(220, this.name + ' ESMTP' + (this._server.options.banner ? ' ' + this._server.options.banner : ''));
callback();
};
/**
* Upgrades connection to TLS if possible

@@ -737,1 +834,48 @@ */

};
// Dummy handlers for some old sendmail specific commands
/**
* Processes sendmail WIZ command, upgrades to "wizard mode"
*/
SMTPConnection.prototype.handler_WIZ = function(command, callback) {
var args = command.toString().trim().split(/\s+/);
var password;
args.shift(); // remove WIZ
password = (args.shift() || '').toString();
// require password argument
if (!password) {
this.send(500, 'You are no wizard!');
return callback();
}
// all passwords pass validation, so everyone is a wizard!
this.session.isWizard = true;
this.send(200, 'Please pass, oh mighty wizard');
callback();
};
/**
* Processes sendmail SHELL command, should return interactive shell but this is a dummy function
* so no actual shell is provided to the client
*/
SMTPConnection.prototype.handler_SHELL = function(command, callback) {
if (!this.session.isWizard) {
this.send(500, 'Mere mortals musn\'t mutter that mantra');
return callback();
}
this._server.logger.info('[%s] Client tried to invoke SHELL', this._id);
this.send(500, 'Error: Invoking shell is not allowed. This incident will be reported.');
callback();
};
/**
* Processes sendmail KILL command
*/
SMTPConnection.prototype.handler_KILL = function(command, callback) {
this.send(500, 'Can\'t kill Mom');
callback();
};

@@ -7,2 +7,4 @@ 'use strict';

var tlsDefaults = {
// pregenerated default certificates for localhost
// obviusly, do not use in production
key: '-----BEGIN RSA PRIVATE KEY-----\n' +

@@ -99,2 +101,2 @@ 'MIIEpAIBAAKCAQEA6Z5Qqhw+oWfhtEiMHE32Ht94mwTBpAfjt3vPpX8M7DMCTwHs\n' +

return result;
}
}
{
"name": "smtp-server",
"version": "1.6.0",
"version": "1.7.0",
"description": "Create custom SMTP servers on the fly",

@@ -13,3 +13,3 @@ "main": "lib/smtp-server.js",

"devDependencies": {
"chai": "^3.3.0",
"chai": "^3.4.0",
"grunt": "^0.4.5",

@@ -16,0 +16,0 @@ "grunt-contrib-jshint": "^0.11.3",

@@ -44,2 +44,3 @@ # smtp-server

* **options.useProxy** boolean, if set to true expects to be behind a proxy that emits a [PROXY header](http://www.haproxy.org/download/1.5/doc/proxy-protocol.txt) (version 1 only)
* **options.useXClient** boolean, if set to true, enables usage of [XCLIENT](http://www.postfix.org/XCLIENT_README.html) extension to override connection properties
* **options.socketTimeout** how many milliseconds of inactivity to allow before disconnecting the client (defaults to 1 minute)

@@ -208,3 +209,3 @@ * **options.closeTimeout** how many millisceonds to wait before disconnecting pending connections once server.close() has been called (defaults to 30 seconds)

var server = new SMTPServer({
onConnect: function(address, session, callback){
onConnect: function(session, callback){
if(session.remoteAddress === '127.0.0.1'){

@@ -211,0 +212,0 @@ return callback(new Error('No connections from localhost allowed'));

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc