Permalink
Browse files

added CRAM-MD5 + CRAM-SHA1 support

  • Loading branch information...
1 parent 57d735e commit 9f72e8b3e5de8517683b774b26b775f19bce825d andris9 committed Aug 24, 2011
Showing with 72 additions and 5 deletions.
  1. +72 −5 lib/engines/SMTP.js
View
@@ -149,6 +149,8 @@ function SMTPClient(host, port, options){
this.remote_auth_plain = false; // Does the server support AUTH PLAIN
this.remote_auth_login = false; // Does the server support AUTH LOGIN
+ this.remote_auth_cram_md5 = false; // Does the server support CRAM-MD5
+ this.remote_auth_cram_sha1 = false; // Does the server support CRAM-SHA1
// Not so public properties
// ------------------------
@@ -409,11 +411,16 @@ SMTPClient.prototype._loginHandler = function(callback){
}else if(this.remote_auth_login){
// use AUTH LOGIN
this._authLogin(callback);
+ }else if(this.remote_auth_cram_md5){
+ // use AUTH CRAM-MD5
+ this._authCram("MD5", callback);
+ }else if(this.remote_auth_cram_sha1){
+ // use AUTH CRAM-SHA1
+ this._authCram("SHA1", callback);
}else{
// try AUTH PLAIN anyway
this._authPlain(callback);
}
- // TODO: Add CRAM-MD5 authentication as well
}
};
@@ -500,6 +507,55 @@ SMTPClient.prototype._authLogin = function(callback){
};
/**
+ * smtp.SMTPClient#_authCram(method, callback) -> undefined
+ * - method (String): either MD5 or SHA1 indicating the hash type used
+ * - callback (Function): function to be run after successful login
+ *
+ * Performs an AUTH CRAM-MD5 login
+ *
+ * C: AUTH CRAM-MD5
+ * S: 334 SECRET
+ * C: BASE64(USERNAME MD5(PASS+SECRET))
+ *
+ * NB! Untested against live server with CRAM support
+ **/
+SMTPClient.prototype._authCram = function(method, callback){
+
+ this.send("AUTH CRAM-" + method, (function(error, message){
+ if(error){
+ this.emit("error", error);
+ this.close();
+ return;
+ }
+
+ if ( message.trim().indexOf('334') != 0 ){
+ // bad server response
+ this.emit('error', new Error('bad server response - ' + message.trim()));
+ this.close();
+ return;
+ }
+
+ var hmac = crypto.createHmac(method, this.options.pass);
+ hmac.update(new Buffer(message.substring(3), 'base64').toString('ascii'));
+
+ this.send(new Buffer(this.options.user + " " + hmac.digest('hex')).toString("base64"), (function(error, message){
+ if(error){
+ this.emit("error", error);
+ this.close();
+ return;
+ }
+
+ // login success
+ this.logged_in = true;
+ this.emit("auth");
+ callback();
+
+ }).bind(this));
+
+ }).bind(this));
+};
+
+/**
* smtp.SMTPClient#_dataListener(data) -> undefined
* - data(String): String received from the server
*
@@ -631,16 +687,27 @@ SMTPClient.prototype._handshake = function(callback){
if(data.match(/PIPELINING/i)){
this.remote_pipelining = true;
}
-
- // check for pipelining support
+
+ // check for auth plain support
if(data.match(/AUTH(?:\s+[^\n]*\s+|\s+)PLAIN/i)){
this.remote_auth_plain = true;
}
- // check for pipelining support
+
+ // check for auth login support
if(data.match(/AUTH(?:\s+[^\n]*\s+|\s+)LOGIN/i)){
this.remote_auth_login = true;
}
-
+
+ // check for auth cram-md5 support
+ if(data.match(/AUTH(?:\s+[^\n]*\s+|\s+)CRAM-MD5/i)){
+ this.remote_auth_cram_md5 = true;
+ }
+
+ // check for auth cram-sha1 support
+ if(data.match(/AUTH(?:\s+[^\n]*\s+|\s+)CRAM-SHA1/i)){
+ this.remote_auth_cram_sha1 = true;
+ }
+
// check for TLS support
if(data.match(/STARTTLS/i)){
if(!this.remote_starttls) {

0 comments on commit 9f72e8b

Please sign in to comment.