diff --git a/lib/Connection.js b/lib/Connection.js index 57b83384..f585d19e 100644 --- a/lib/Connection.js +++ b/lib/Connection.js @@ -1,4 +1,5 @@ var tls = require('tls'), + crypto = require('crypto'), Socket = require('net').Socket, EventEmitter = require('events').EventEmitter, inherits = require('util').inherits, @@ -242,6 +243,8 @@ Connection.prototype.connect = function() { self._curReq.oauthError = new Buffer(info.text, 'base64').toString('utf8'); self.debug && self.debug('=> ' + inspect(CRLF)); self._sock.write(CRLF); + } else if (/^AUTHENTICATE CRAM-MD5/.test(self._curReq.fullcmd)) { + self._authCRAMMD5(info.text); } else if (type === 'APPEND') { self._sockWriteAppendData(self._curReq.appendData); } else if (self._curReq.lines && self._curReq.lines.length) { @@ -1653,9 +1656,14 @@ Connection.prototype._login = function() { cmd += ' ' + escape(self._config.xoauth2); self._enqueue(cmd, checkCaps); } else if (self._config.user && self._config.password) { + if (self.serverSupports('AUTH=CRAM-MD5')) { + cmd = 'AUTHENTICATE CRAM-MD5'; + } else { + cmd = 'LOGIN "' + escape(self._config.user) + '" "' + + escape(self._config.password) + '"'; + } self._caps = undefined; - self._enqueue('LOGIN "' + escape(self._config.user) + '" "' - + escape(self._config.password) + '"', checkCaps); + self._enqueue(cmd, checkCaps); } else { err = new Error('No supported authentication method(s) available. ' + 'Unable to login.'); @@ -1667,6 +1675,17 @@ Connection.prototype._login = function() { }); }; +Connection.prototype._authCRAMMD5 = function(secret) { + var decodedSecret, hmac, response; + decodedSecret = new Buffer(secret, 'base64').toString('utf8'); + hmac = crypto.createHmac('md5', this._config.password) + .update(decodedSecret) + .digest('hex'); + response = new Buffer(this._config.user + ' ' + hmac).toString('base64'); + this.debug && this.debug('=> ' + response); + this._sock.write(response + CRLF, 'utf8'); +}; + Connection.prototype._starttls = function() { var self = this; this._enqueue('STARTTLS', function(err) {