Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Cleanup SMTP Auth code, add in basic test case

  • Loading branch information...
commit 9e9d87417cb8d9be4e15fffa3c667172a8cd8600 1 parent 34b8360
@hayesgm hayesgm authored
Showing with 134 additions and 13 deletions.
  1. +29 −13 smtp_client.js
  2. +105 −0 tests/smtp_client/auth.js
View
42 smtp_client.js
@@ -198,6 +198,7 @@ SMTPClient.prototype.release = function () {
return;
}
this.state = STATE_RELEASED;
+ this.authenticated = false;
this.removeAllListeners('greeting');
this.removeAllListeners('capabilities');
this.removeAllListeners('xclient');
@@ -349,23 +350,38 @@ exports.get_client_plugin = function (plugin, connection, config, callback) {
return;
}
}
+
+ var auth_matches;
+ if (auth_matches = smtp_client.response[line].match(/^AUTH (.*)$/)) {
+ auth_matches = auth_matches[1].split(' ');
+ for (var i = 0; i < auth_matches.length; i++) {
+ connection.auth_capibilities.push(auth_matches[i].toLowerCase());
+ }
+ }
}
});
smtp_client.on('helo', function () {
- if (config.auth && !this.authentiated) {
- switch (config.auth.type) {
- case 'plain':
- connection.logdebug(['SMTP Authenticating as', config.auth.user]);
- smtp_client.send_command('AUTH',
- 'PLAIN ' + base64("\0" + config.auth.user + "\0" + config.auth.pass) );
- this.authenticated = true;
- break;
- case null:
- case undefined:
- break; // Nothing to do here
- default:
- throw new Error("Unknown AUTH type: " + config.auth.type);
+ if (config.auth && !smtp_client.authentiated) {
+ if (config.auth.type === null || typeof(config.auth.type) === 'undefined') { return; } // Ignore blank
+ var auth_type = config.auth.type.toLowerCase();
+ if (connection.auth_capibilities.indexOf(auth_type) == -1) {
+ throw new Error("Auth type \"" + auth_type + "\" not supported by server (supports: " + connection.auth_capibilities.join(',') + ")")
+ }
+ switch (auth_type) {
+ case 'plain':
+ if (!config.auth.user || !config.auth.pass) {
+ throw new Error("Must include auth.user and auth.pass for PLAIN auth.");
+ }
+ logger.logdebug('[smtp_client_pool] uuid=' + smtp_client.uuid + ' authenticating as "' + config.auth.user + '"');
+ smtp_client.send_command('AUTH',
+ 'PLAIN ' + base64(config.auth.user + "\0" + config.auth.user + "\0" + config.auth.pass) );
+ smtp_client.authenticated = true;
+ break;
+ case 'cram-md5':
+ throw new Error("Not implemented");
+ default:
+ throw new Error("Unknown AUTH type: " + auth_type);
}
}
});
View
105 tests/smtp_client/auth.js
@@ -0,0 +1,105 @@
+test.expect(24);
+var server = {notes: {}};
+
+exports.get_pool(server);
+var pool_name = '25:localhost:300';
+test.equals(1, Object.keys(server.notes.pool).length);
+test.equals(pool_name, Object.keys(server.notes.pool)[0]);
+test.equals(0, server.notes.pool[pool_name].getPoolSize());
+test.equals(0, server.notes.pool[pool_name].availableObjectsCount());
+
+exports.get_client(server, function(err, smtp_client) {
+ test.equals(null, err);
+ test.equals(1, server.notes.pool[pool_name].getPoolSize());
+ test.equals(0, server.notes.pool[pool_name].availableObjectsCount());
+
+ var data = [];
+ var reading_body = false;
+ data.push('220 hi');
+
+ smtp_client.on('greeting', function (command) {
+ test.equals(smtp_client.response[0], 'hi');
+ test.equals('EHLO', command);
+ smtp_client.send_command(command, 'example.com');
+ });
+
+ data.push('EHLO example.com');
+ data.push('250 hello');
+
+ smtp_client.on('helo', function () {
+ test.equals(smtp_client.response[0], 'hello');
+ smtp_client.send_command('AUTH', 'PLAIN AHRlc3QAdGVzdHBhc3M=');
+ smtp_client.send_command('MAIL', 'FROM: me@example.com');
+ });
+
+ data.push('AUTH PLAIN AHRlc3QAdGVzdHBhc3M='); // test/testpass
+ data.push('235 Authentication successful.');
+
+ data.push('MAIL FROM: me@example.com');
+ data.push('250 sender ok');
+
+ smtp_client.on('mail', function () {
+ test.equals(smtp_client.response[0], 'sender ok');
+ smtp_client.send_command('RCPT', 'TO: you@example.com');
+ });
+
+ data.push('RCPT TO: you@example.com');
+ data.push('250 recipient ok');
+
+ smtp_client.on('rcpt', function () {
+ test.equals(smtp_client.response[0], 'recipient ok');
+ smtp_client.send_command('DATA');
+ });
+
+ data.push('DATA');
+ data.push('354 go ahead');
+
+ smtp_client.on('data', function () {
+ test.equals(smtp_client.response[0], 'go ahead');
+ smtp_client.start_data(['Header: test\r\n', '\r\n', 'hi\r\n']);
+ });
+
+ data.push('Header: test');
+ data.push('');
+ data.push('hi');
+ data.push('.');
+ data.push('250 message queued');
+
+ smtp_client.on('dot', function () {
+ test.equals(smtp_client.response[0], 'message queued');
+ smtp_client.send_command('QUIT');
+ });
+
+ data.push('QUIT');
+ data.push('221 goodbye');
+
+ smtp_client.on('quit', function () {
+ test.equals(smtp_client.response[0], 'goodbye');
+ test.done();
+ });
+
+ smtp_client.socket.write = function (line) {
+ if (data.length == 0) {
+ test.ok(false);
+ return;
+ }
+ test.equals(data.shift() + '\r\n', line);
+ if (reading_body && line == '.\r\n') {
+ reading_body = false;
+ }
+ if (!reading_body) {
+ if (line == 'DATA\r\n') {
+ reading_body = true;
+ }
+ while (true) {
+ var line = data.shift();
+ this.emit('line', line + '\r\n');
+ if (line[3] == ' ') break;
+ }
+ }
+
+ return true;
+ };
+
+ smtp_client.socket.emit('line', data.shift());
+});
Please sign in to comment.
Something went wrong with that request. Please try again.