This commit is contained in:
Andris Reinman 2017-04-09 23:40:16 +03:00
parent 34be6c2b39
commit 8e498903a5

View file

@ -171,15 +171,44 @@ class POP3Connection extends EventEmitter {
return;
}
let line = this.queue.shift().trim();
if (typeof this._nextHandler === 'function') {
let handler = this._nextHandler;
this._nextHandler = null;
this._server.logger.debug({
tnx: 'receive',
cid: this._id,
user: this.session.user && this.session.user.username
}, 'C: <%s bytes of continue data>', Buffer.byteLength(line));
return handler(line, err => {
if (err) {
this._server.logger.info({
err,
tnx: '+',
cid: this._id,
host: this.remoteAddress
}, 'Error processing continue data. %s', err.message);
this.send('-ERR ' + err.message);
this.close();
} else {
this.processQueue();
}
});
}
let parts = line.split(' ');
let command = parts.shift().toUpperCase();
let args = parts.join(' ');
let logLine = (line || '').toString();
if (/^(PASS|AUTH PLAIN)\s+[^\s]+/i.test(line)) {
logLine = logLine.replace(/[^\s]+$/, '*hidden*');
}
this._server.logger.debug({
tnx: 'receive',
cid: this._id,
user: this.session.user && this.session.user.username
}, 'C:', (line || '').toString());
}, 'C:', logLine);
if (typeof this['command_' + command] === 'function') {
this['command_' + command](args, err => {
@ -310,70 +339,26 @@ class POP3Connection extends EventEmitter {
let params = args.split(/\s+/);
let mechanism = params.shift().toUpperCase();
let plain = params.shift();
if (mechanism !== 'PLAIN') {
this.send('-ERR unsupported SASL mechanism');
return next();
}
if (params.length || !/^[a-zA-Z0-9+\/]+=+?$/.test(plain)) {
if (!params.length) {
this.send('+');
this._nextHandler = (args, next) => this.authPlain(args, next);
return next();
}
let plain = params.shift();
if (params.length) {
this.send('-ERR malformed command');
return next();
}
let credentials = Buffer.from(plain, 'base64').toString().split('\x00');
if (credentials.length !== 3) {
this.send('-ERR malformed command');
return next();
}
let username = credentials[1] || credentials[0] || '';
let password = credentials[2] || '';
this._server.onAuth({
method: 'PLAIN',
username,
password
}, this.session, (err, response) => {
if (err) {
this._server.logger.info({
err,
tnx: 'autherror',
cid: this._id,
method: 'PLAIN',
user: username
}, 'Authentication error for %s using %s. %s', username, 'PLAIN', err.message);
return next(err);
}
if (!response.user) {
this._server.logger.info({
tnx: 'authfail',
cid: this._id,
method: 'PLAIN',
user: username
}, 'Authentication failed for %s using %s', username, 'PLAIN');
this.send('-ERR [AUTH] ' + (response.message || 'Username and password not accepted'));
return next();
}
this._server.logger.info({
tnx: 'auth',
cid: this._id,
method: 'PLAIN',
user: username
}, '%s authenticated using %s', username, 'PLAIN');
this.session.user = response.user;
this.openMailbox(err => {
if (err) {
return next(err);
}
next();
});
});
this.authPlain(plain, next);
}
// https://tools.ietf.org/html/rfc1939#page-9
@ -662,7 +647,7 @@ class POP3Connection extends EventEmitter {
} else {
data = '';
}
this.write(Buffer.from(headers.replace(/^\./gm,'..'), 'binary'));
this.write(Buffer.from(headers.replace(/^\./gm, '..'), 'binary'));
}
}
if (headers) {
@ -682,7 +667,7 @@ class POP3Connection extends EventEmitter {
} else {
data = '';
}
this.write(Buffer.from(line.replace(/^\./gm,'..'), 'binary'));
this.write(Buffer.from(line.replace(/^\./gm, '..'), 'binary'));
if (linesSent >= lines) {
finished = true;
if (typeof stream.abort === 'function') {
@ -705,6 +690,66 @@ class POP3Connection extends EventEmitter {
});
}
authPlain(plain, next) {
if (!/^[a-zA-Z0-9+\/]+=+?$/.test(plain)) {
this.send('-ERR malformed command');
return next();
}
let credentials = Buffer.from(plain, 'base64').toString().split('\x00');
if (credentials.length !== 3) {
this.send('-ERR malformed command');
return next();
}
let username = credentials[1] || credentials[0] || '';
let password = credentials[2] || '';
this._server.onAuth({
method: 'PLAIN',
username,
password
}, this.session, (err, response) => {
if (err) {
this._server.logger.info({
err,
tnx: 'autherror',
cid: this._id,
method: 'PLAIN',
user: username
}, 'Authentication error for %s using %s. %s', username, 'PLAIN', err.message);
return next(err);
}
if (!response.user) {
this._server.logger.info({
tnx: 'authfail',
cid: this._id,
method: 'PLAIN',
user: username
}, 'Authentication failed for %s using %s', username, 'PLAIN');
this.send('-ERR [AUTH] ' + (response.message || 'Username and password not accepted'));
return next();
}
this._server.logger.info({
tnx: 'auth',
cid: this._id,
method: 'PLAIN',
user: username
}, '%s authenticated using %s', username, 'PLAIN');
this.session.user = response.user;
this.openMailbox(err => {
if (err) {
return next(err);
}
next();
});
});
}
openMailbox(next) {
this._server.onListMessages(this.session, (err, listing) => {
if (err) {