diff --git a/src/mailboxdb.js b/src/mailboxdb.js index 6ee5a780e..0ce7ed133 100644 --- a/src/mailboxdb.js +++ b/src/mailboxdb.js @@ -41,8 +41,9 @@ function del(id, callback) { assert.strictEqual(typeof id, 'string'); assert.strictEqual(typeof callback, 'function'); - database.query('DELETE FROM mailboxes WHERE id=?', [ id ], function (error) { + database.query('DELETE FROM mailboxes WHERE id=?', [ id ], function (error, result) { if (error) return callback(new DatabaseError(DatabaseError.INTERNAL_ERROR, error)); + if (result.affectedRows === 0) return callback(new DatabaseError(DatabaseError.NOT_FOUND)); callback(null); }); diff --git a/src/mailboxes.js b/src/mailboxes.js index 9be831c5c..bca1129af 100644 --- a/src/mailboxes.js +++ b/src/mailboxes.js @@ -4,7 +4,9 @@ exports = module.exports = { add: add, del: del, get: get, - getAll: getAll + getAll: getAll, + + MailboxError: MailboxError }; var assert = require('assert'), @@ -33,9 +35,18 @@ function MailboxError(reason, errorOrMessage) { util.inherits(MailboxError, Error); MailboxError.ALREADY_EXISTS = 'already exists'; MailboxError.BAD_NAME = 'bad name'; +MailboxError.NOT_FOUND = 'not found'; MailboxError.INTERNAL_ERROR = 'internal error'; function validateName(name) { + var RESERVED_NAMES = [ 'no-reply', 'postmaster', 'mailer-daemon' ]; + + if (name.length < 2) return new MailboxError(MailboxError.BAD_NAME, 'Name too small'); + if (name.length > 127) return new MailboxError(MailboxError.BAD_NAME, 'Name too long'); + if (RESERVED_NAMES.indexOf(name) !== -1) return new MailboxError(MailboxError.BAD_NAME, 'Name is reserved'); + + if (/[^a-zA-Z0-9.]/.test(name)) return new MailboxError(MailboxError.BAD_NAME, 'Name can only contain alphanumerals and dot'); + return null; } @@ -43,11 +54,13 @@ function add(name, callback) { assert.strictEqual(typeof name, 'string'); assert.strictEqual(typeof callback, 'function'); + name = name.toLowerCase(); + var error = validateName(name); if (error) return callback(error); mailboxdb.add(name /* id */, name, function (error) { - if (error && error.reason === MailboxError.ALREADY_EXISTS) return callback(new MailboxError(MailboxError.ALREADY_EXISTS)); + if (error && error.reason === DatabaseError.ALREADY_EXISTS) return callback(new MailboxError(MailboxError.ALREADY_EXISTS)); if (error) return callback(new MailboxError(MailboxError.INTERNAL_ERROR, error)); var mailbox = { @@ -60,10 +73,11 @@ function add(name, callback) { } function del(id, callback) { - assert.strictEqual(typeof name, 'string'); + assert.strictEqual(typeof id, 'string'); assert.strictEqual(typeof callback, 'function'); - mailboxdb.del(name, function (error) { + mailboxdb.del(id, function (error) { + if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new MailboxError(MailboxError.NOT_FOUND)); if (error) return callback(new MailboxError(MailboxError.INTERNAL_ERROR, error)); callback(); @@ -75,6 +89,7 @@ function get(id, callback) { assert.strictEqual(typeof callback, 'function'); mailboxdb.get(id, function (error, mailbox) { + if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new MailboxError(MailboxError.NOT_FOUND)); if (error) return callback(new MailboxError(MailboxError.INTERNAL_ERROR, error)); callback(null, mailbox); diff --git a/src/test/mailboxes-test.js b/src/test/mailboxes-test.js new file mode 100644 index 000000000..8822c4bdc --- /dev/null +++ b/src/test/mailboxes-test.js @@ -0,0 +1,111 @@ +/* global it:false */ +/* global describe:false */ +/* global before:false */ +/* global after:false */ + +'use strict'; + +var database = require('../database.js'), + expect = require('expect.js'), + mailboxes = require('../mailboxes.js'), + MailboxError = mailboxes.MailboxError, + hat = require('hat'); + +var USER_0 = { + id: 'uuid213', + username: 'uuid213', + password: 'secret', + email: 'safe@me.com', + admin: false, + salt: 'morton', + createdAt: 'sometime back', + modifiedAt: 'now', + resetToken: hat(256), + displayName: '', + showTutorial: false +}; + +function setup(done) { + // ensure data/config/mount paths + database.initialize(function (error) { + expect(error).to.be(null); + + database._clear(done); + }); +} + +function cleanup(done) { + database._clear(done); +} + +var MAILBOX_ID = 'test'; + +describe('Mailboxes', function () { + before(setup); + after(cleanup); + + it('cannot create mailbox - too small', function (done) { + mailboxes.add('a', function (error) { + expect(error.reason).to.be(MailboxError.BAD_NAME); + done(); + }); + }); + + it('cannot create mailbox - too big', function (done) { + mailboxes.add(new Array(129).join('a'), function (error) { + expect(error.reason).to.be(MailboxError.BAD_NAME); + done(); + }); + }); + + it('cannot create mailbox - bad name', function (done) { + mailboxes.add('bad:name', function (error) { + expect(error.reason).to.be(MailboxError.BAD_NAME); + done(); + }); + }); + + it('cannot create mailbox - reserved', function (done) { + mailboxes.add('no-reply', function (error) { + expect(error.reason).to.be(MailboxError.BAD_NAME); + done(); + }); + }); + + it('can create valid mailbox', function (done) { + mailboxes.add(MAILBOX_ID, function (error) { + expect(error).to.be(null); + done(); + }); + }); + + it('cannot add existing mailbox', function (done) { + mailboxes.add(MAILBOX_ID, function (error) { + expect(error.reason).to.be(MailboxError.ALREADY_EXISTS); + done(); + }); + }); + + it('cannot get invalid mailbox', function (done) { + mailboxes.get('sometrandom', function (error) { + expect(error.reason).to.be(MailboxError.NOT_FOUND); + done(); + }); + }); + + it('can get valid mailbox', function (done) { + mailboxes.get(MAILBOX_ID, function (error, group) { + expect(error).to.be(null); + expect(group.name).to.equal(MAILBOX_ID); + done(); + }); + }); + + it('cannot delete invalid mailbox', function (done) { + mailboxes.del('random', function (error) { + expect(error.reason).to.be(MailboxError.NOT_FOUND); + done(); + }); + }); +}); +