wildduck/imap-core/lib/commands/starttls.js
2017-10-05 15:14:43 +03:00

89 lines
2.9 KiB
JavaScript

'use strict';
// openssl s_client -starttls imap -crlf -connect localhost:1143
const tls = require('tls');
const SOCKET_TIMEOUT = 30 * 60 * 1000;
module.exports = {
handler(command, callback) {
if (this.secure) {
return callback(null, {
response: 'NO',
message: 'Connection is already secured'
});
}
setImmediate(upgrade.bind(null, this));
callback(null, {
response: 'OK'
});
}
};
/**
* Upgrades current socket to use TLS
* @param {Object} connection IMAPConnection instance
*/
function upgrade(connection) {
connection._socket.unpipe(connection._parser);
connection.writeStream.unpipe(connection._socket);
connection._upgrading = true;
let secureContext = connection._server.secureContext.get('*');
let socketOptions = {
secureContext,
isServer: true,
server: connection._server.server,
SNICallback: (servername, cb) => {
cb(null, connection._server.secureContext.get(connection._server._normalizeHostname(servername)) || connection._server.secureContext.get('*'));
}
};
// Apply additional socket options if these are set in the server options
['requestCert', 'rejectUnauthorized', 'NPNProtocols', 'SNICallback', 'session', 'requestOCSP'].forEach(key => {
if (key in connection._server.options) {
socketOptions[key] = connection._server.options[key];
}
});
// remove all listeners from the original socket besides the error handler
connection._socket.removeAllListeners();
connection._socket.on('error', connection._onError.bind(connection));
// upgrade connection
let secureSocket = new tls.TLSSocket(connection._socket, socketOptions);
secureSocket.once('close', () => connection._onClose());
secureSocket.once('error', err => connection._onError(err));
secureSocket.once('_tlsError', err => connection._onError(err));
secureSocket.once('clientError', err => connection._onError(err));
secureSocket.setTimeout(connection._server.options.socketTimeout || SOCKET_TIMEOUT, () => connection._onTimeout());
secureSocket.on('secure', () => {
connection.secure = true;
connection._socket = secureSocket;
connection._upgrading = false;
let cipher = connection._socket.getCipher();
connection._server.logger.info(
{
tnx: 'starttls',
cid: connection.id,
user: connection.session && connection.session.user && connection.session.user.username,
cipher: cipher && cipher.name
},
'[%s] Connection upgraded to TLS using ',
connection.id,
(cipher && cipher.name) || 'N/A'
);
connection._socket.pipe(connection._parser);
connection.writeStream.pipe(connection._socket);
});
}