Commit 3fec599c authored by Girish Ramakrishnan's avatar Girish Ramakrishnan

remove mail domain add/remove API

merge this as a transaction into domains API

fixes #669
parent e30ea9f1
......@@ -51,16 +51,21 @@ function getAll(callback) {
});
}
function add(name, domain, callback) {
function add(name, data, callback) {
assert.strictEqual(typeof name, 'string');
assert.strictEqual(typeof domain, 'object');
assert.strictEqual(typeof domain.zoneName, 'string');
assert.strictEqual(typeof domain.provider, 'string');
assert.strictEqual(typeof domain.config, 'object');
assert.strictEqual(typeof domain.tlsConfig, 'object');
assert.strictEqual(typeof data, 'object');
assert.strictEqual(typeof data.zoneName, 'string');
assert.strictEqual(typeof data.provider, 'string');
assert.strictEqual(typeof data.config, 'object');
assert.strictEqual(typeof data.tlsConfig, 'object');
assert.strictEqual(typeof callback, 'function');
database.query('INSERT INTO domains (domain, zoneName, provider, configJson, tlsConfigJson) VALUES (?, ?, ?, ?, ?)', [ name, domain.zoneName, domain.provider, JSON.stringify(domain.config), JSON.stringify(domain.tlsConfig) ], function (error) {
let queries = [
{ query: 'INSERT INTO domains (domain, zoneName, provider, configJson, tlsConfigJson) VALUES (?, ?, ?, ?, ?)', args: [ name, data.zoneName, data.provider, JSON.stringify(data.config), JSON.stringify(data.tlsConfig) ] },
{ query: 'INSERT INTO mail (domain, dkimSelector) VALUES (?, ?)', args: [ name, data.dkimSelector || 'cloudron' ] },
];
database.transaction(queries, function (error) {
if (error && error.code === 'ER_DUP_ENTRY') return callback(new BoxError(BoxError.ALREADY_EXISTS, error));
if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error));
......@@ -100,7 +105,12 @@ function del(domain, callback) {
assert.strictEqual(typeof domain, 'string');
assert.strictEqual(typeof callback, 'function');
database.query('DELETE FROM domains WHERE domain=?', [ domain ], function (error, result) {
let queries = [
{ query: 'DELETE FROM mail WHERE domain = ?', args: [ domain ] },
{ query: 'DELETE FROM domains WHERE domain = ?', args: [ domain ] },
];
database.transaction(queries, function (error, results) {
if (error && error.code === 'ER_ROW_IS_REFERENCED_2') {
if (error.message.indexOf('apps_mailDomain_constraint') !== -1) return callback(new BoxError(BoxError.CONFLICT, 'Domain is in use by an app or the mailbox of an app. Check the domains of apps and the Email section of each app.'));
if (error.message.indexOf('subdomains') !== -1) return callback(new BoxError(BoxError.CONFLICT, 'Domain is in use by one or more app(s).'));
......@@ -108,8 +118,9 @@ function del(domain, callback) {
return callback(new BoxError(BoxError.CONFLICT, error.message));
}
if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error));
if (result.affectedRows === 0) return callback(new BoxError(BoxError.NOT_FOUND, 'Domain not found'));
if (results[1].affectedRows !== 1) return callback(new BoxError(BoxError.NOT_FOUND, 'Domain not found'));
callback(null);
});
......
......@@ -40,6 +40,7 @@ var assert = require('assert'),
debug = require('debug')('box:domains'),
domaindb = require('./domaindb.js'),
eventlog = require('./eventlog.js'),
mail = require('./mail.js'),
reverseProxy = require('./reverseproxy.js'),
safe = require('safetydance'),
settings = require('./settings.js'),
......@@ -48,6 +49,8 @@ var assert = require('assert'),
util = require('util'),
_ = require('underscore');
const NOOP_CALLBACK = function (error) { if (error) debug(error); };
// choose which subdomain backend we use for test purpose we use route53
function api(provider) {
assert.strictEqual(typeof provider, 'string');
......@@ -171,7 +174,7 @@ function add(domain, data, auditSource, callback) {
assert.strictEqual(typeof data.tlsConfig, 'object');
assert.strictEqual(typeof callback, 'function');
let { zoneName, provider, config, fallbackCertificate, tlsConfig } = data;
let { zoneName, provider, config, fallbackCertificate, tlsConfig, dkimSelector } = data;
if (!tld.isValid(domain)) return callback(new BoxError(BoxError.BAD_FIELD, 'Invalid domain', { field: 'domain' }));
if (domain.endsWith('.')) return callback(new BoxError(BoxError.BAD_FIELD, 'Invalid domain', { field: 'domain' }));
......@@ -194,10 +197,12 @@ function add(domain, data, auditSource, callback) {
let error = validateTlsConfig(tlsConfig, provider);
if (error) return callback(error);
if (!dkimSelector) dkimSelector = 'cloudron-' + settings.adminDomain().replace(/\./g, '');
verifyDnsConfig(config, domain, zoneName, provider, function (error, sanitizedConfig) {
if (error) return callback(error);
domaindb.add(domain, { zoneName: zoneName, provider: provider, config: sanitizedConfig, tlsConfig: tlsConfig }, function (error) {
domaindb.add(domain, { zoneName, provider, config: sanitizedConfig, tlsConfig, dkimSelector }, function (error) {
if (error) return callback(error);
reverseProxy.setFallbackCertificate(domain, fallbackCertificate, function (error) {
......@@ -205,6 +210,8 @@ function add(domain, data, auditSource, callback) {
eventlog.add(eventlog.ACTION_DOMAIN_ADD, auditSource, { domain, zoneName, provider });
mail.onDomainAdded(domain, NOOP_CALLBACK);
callback();
});
});
......@@ -314,6 +321,8 @@ function del(domain, auditSource, callback) {
eventlog.add(eventlog.ACTION_DOMAIN_REMOVE, auditSource, { domain });
mail.onDomainRemoved(domain, NOOP_CALLBACK);
return callback(null);
});
}
......
......@@ -7,10 +7,11 @@ exports = module.exports = {
getDomains: getDomains,
getDomain: getDomain,
addDomain: addDomain,
removeDomain: removeDomain,
clearDomains: clearDomains,
onDomainAdded: onDomainAdded,
onDomainRemoved: onDomainRemoved,
removePrivateFields: removePrivateFields,
setDnsRecords: setDnsRecords,
......@@ -904,37 +905,21 @@ function onMailFqdnChanged(callback) {
});
}
function addDomain(domain, callback) {
function onDomainAdded(domain, callback) {
assert.strictEqual(typeof domain, 'string');
assert.strictEqual(typeof callback, 'function');
const dkimSelector = domain === settings.adminDomain() ? 'cloudron' : ('cloudron-' + settings.adminDomain().replace(/\./g, ''));
maildb.add(domain, { dkimSelector }, function (error) {
if (error) return callback(error);
async.series([
upsertDnsRecords.bind(null, domain, settings.mailFqdn()), // do this first to ensure DKIM keys
restartMailIfActivated
], NOOP_CALLBACK); // do these asynchronously
callback();
});
async.series([
upsertDnsRecords.bind(null, domain, settings.mailFqdn()), // do this first to ensure DKIM keys
restartMailIfActivated
], callback);
}
function removeDomain(domain, callback) {
function onDomainRemoved(domain, callback) {
assert.strictEqual(typeof domain, 'string');
assert.strictEqual(typeof callback, 'function');
if (domain === settings.adminDomain()) return callback(new BoxError(BoxError.CONFLICT));
maildb.del(domain, function (error) {
if (error) return callback(error);
restartMail(NOOP_CALLBACK);
callback();
});
restartMail(callback);
}
function clearDomains(callback) {
......
'use strict';
exports = module.exports = {
add: add,
del: del,
get: get,
list: list,
update: update,
......@@ -34,20 +32,6 @@ function postProcess(data) {
return data;
}
function add(domain, data, callback) {
assert.strictEqual(typeof domain, 'string');
assert.strictEqual(typeof data, 'object');
assert.strictEqual(typeof callback, 'function');
database.query('INSERT INTO mail (domain, dkimSelector) VALUES (?, ?)', [ domain, data.dkimSelector || 'cloudron' ], function (error) {
if (error && error.code === 'ER_DUP_ENTRY') return callback(new BoxError(BoxError.ALREADY_EXISTS, 'mail domain already exists'));
if (error && error.code === 'ER_NO_REFERENCED_ROW_2') return callback(new BoxError(BoxError.NOT_FOUND), 'no such domain');
if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error));
callback(null);
});
}
function clear(callback) {
assert.strictEqual(typeof callback, 'function');
......@@ -58,20 +42,6 @@ function clear(callback) {
});
}
function del(domain, callback) {
assert.strictEqual(typeof domain, 'string');
assert.strictEqual(typeof callback, 'function');
// deletes aliases as well
database.query('DELETE FROM mail WHERE domain=?', [ domain ], function (error, result) {
if (error && error.code === 'ER_ROW_IS_REFERENCED_2') return callback(new BoxError(BoxError.CONFLICT));
if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error));
if (result.affectedRows === 0) return callback(new BoxError(BoxError.NOT_FOUND, 'Mail domain not found'));
callback(null);
});
}
function get(domain, callback) {
assert.strictEqual(typeof domain, 'string');
assert.strictEqual(typeof callback, 'function');
......
......@@ -121,7 +121,8 @@ function setup(dnsConfig, sysinfoConfig, auditSource, callback) {
provider: dnsConfig.provider,
config: dnsConfig.config,
fallbackCertificate: dnsConfig.fallbackCertificate || null,
tlsConfig: dnsConfig.tlsConfig || { provider: 'letsencrypt-prod' }
tlsConfig: dnsConfig.tlsConfig || { provider: 'letsencrypt-prod' },
dkimSelector: 'cloudron'
};
domains.add(domain, data, auditSource, function (error) {
......@@ -137,7 +138,6 @@ function setup(dnsConfig, sysinfoConfig, auditSource, callback) {
settings.setSysinfoConfig.bind(null, sysinfoConfig),
domains.prepareDashboardDomain.bind(null, domain, auditSource, (progress) => setProgress('setup', progress.message, NOOP_CALLBACK)),
cloudron.setDashboardDomain.bind(null, domain, auditSource),
mail.addDomain.bind(null, domain), // this relies on settings.mailFqdn() and settings.adminDomain()
setProgress.bind(null, 'setup', 'Done'),
eventlog.add.bind(null, eventlog.ACTION_PROVISION, auditSource, { })
], function (error) {
......
......@@ -2,8 +2,6 @@
exports = module.exports = {
getDomain: getDomain,
addDomain: addDomain,
removeDomain: removeDomain,
setDnsRecords: setDnsRecords,
......@@ -50,18 +48,6 @@ function getDomain(req, res, next) {
});
}
function addDomain(req, res, next) {
assert.strictEqual(typeof req.body, 'object');
if (typeof req.body.domain !== 'string') return next(new HttpError(400, 'domain must be a string'));
mail.addDomain(req.body.domain, function (error) {
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(201, { domain: req.body.domain }));
});
}
function setDnsRecords(req, res, next) {
assert.strictEqual(typeof req.body, 'object');
assert.strictEqual(typeof req.params.domain, 'string');
......@@ -77,16 +63,6 @@ function setDnsRecords(req, res, next) {
});
}
function removeDomain(req, res, next) {
assert.strictEqual(typeof req.params.domain, 'string');
mail.removeDomain(req.params.domain, function (error) {
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(204));
});
}
function getStatus(req, res, next) {
assert.strictEqual(typeof req.params.domain, 'string');
......
This diff is collapsed.
......@@ -47,7 +47,6 @@ function setup(done) {
server.start,
database._clear,
domains.add.bind(null, DOMAIN_0.domain, DOMAIN_0, AUDIT_SOURCE),
mail.addDomain.bind(null, DOMAIN_0.domain)
], function (error) {
expect(error).to.not.be.ok();
......
......@@ -253,8 +253,6 @@ function initializeExpressSync() {
}, routes.mailserver.proxy);
router.get ('/api/v1/mail/:domain', token, authorizeAdmin, routes.mail.getDomain);
router.post('/api/v1/mail', token, authorizeAdmin, routes.mail.addDomain);
router.del ('/api/v1/mail/:domain', token, authorizeAdmin, routes.mail.removeDomain);
router.get ('/api/v1/mail/:domain/status', token, authorizeAdmin, routes.mail.getStatus);
router.post('/api/v1/mail/:domain/mail_from_validation', token, authorizeAdmin, routes.mail.setMailFromValidation);
router.post('/api/v1/mail/:domain/catch_all', token, authorizeAdmin, routes.mail.setCatchAllAddress);
......
......@@ -15,6 +15,7 @@ var appdb = require('../appdb.js'),
groupdb = require('../groupdb.js'),
groups = require('../groups.js'),
hat = require('../hat.js'),
settings = require('../settings.js'),
userdb = require('../userdb.js');
let AUDIT_SOURCE = { ip: '1.2.3.4' };
......@@ -173,6 +174,7 @@ describe('Apps', function () {
async.series([
database.initialize,
database._clear,
settings.setAdmin.bind(null, DOMAIN_0.domain, 'my.' + DOMAIN_0.domain),
domains.add.bind(null, DOMAIN_0.domain, DOMAIN_0, AUDIT_SOURCE),
domains.add.bind(null, DOMAIN_1.domain, DOMAIN_1, AUDIT_SOURCE),
userdb.add.bind(null, ADMIN_0.id, ADMIN_0),
......
......@@ -18,6 +18,7 @@ var addons = require('../addons.js'),
net = require('net'),
nock = require('nock'),
paths = require('../paths.js'),
settings = require('../settings.js'),
userdb = require('../userdb.js'),
_ = require('underscore');
......@@ -119,6 +120,7 @@ describe('apptask', function () {
async.series([
database.initialize,
database._clear,
settings.setAdmin.bind(null, DOMAIN_0.domain, 'my.' + DOMAIN_0.domain),
domains.add.bind(null, DOMAIN_0.domain, DOMAIN_0, AUDIT_SOURCE),
userdb.add.bind(null, ADMIN.id, ADMIN),
appdb.add.bind(null, APP.id, APP.appStoreId, APP.manifest, APP.location, APP.domain, APP.portBindings, APP)
......
......@@ -1777,7 +1777,6 @@ describe('database', function () {
before(function (done) {
async.series([
domaindb.add.bind(null, DOMAIN_0.domain, { zoneName: DOMAIN_0.zoneName, provider: DOMAIN_0.provider, config: DOMAIN_0.config, tlsConfig: DOMAIN_0.tlsConfig }),
maildb.add.bind(null, DOMAIN_0.domain, {})
], done);
});
......@@ -1951,23 +1950,6 @@ describe('database', function () {
database._clear(done);
});
it('cannot add non-existing domain', function (done) {
maildb.add(MAIL_DOMAIN_0.domain + 'nope', {}, function (error) {
expect(error).to.be.ok();
expect(error.reason).to.be(BoxError.NOT_FOUND);
done();
});
});
it('can add domain', function (done) {
maildb.add(MAIL_DOMAIN_0.domain, {}, function (error) {
expect(error).to.equal(null);
done();
});
});
it('can get all domains', function (done) {
maildb.list(function (error, result) {
expect(error).to.equal(null);
......
......@@ -88,7 +88,6 @@ function setup(done) {
database._clear.bind(null),
ldapServer.start.bind(null),
domains.add.bind(null, DOMAIN_0.domain, DOMAIN_0, AUDIT_SOURCE),
maildb.add.bind(null, DOMAIN_0.domain, {}),
function (callback) {
users.createOwner(USER_0.username, USER_0.password, USER_0.email, USER_0.displayName, AUDIT_SOURCE, function (error, result) {
if (error) return callback(error);
......
......@@ -34,7 +34,6 @@ function setup(done) {
database._clear,
domains.add.bind(null, DOMAIN_0.domain, DOMAIN_0, AUDIT_SOURCE),
settings.setAdmin.bind(null, DOMAIN_0.domain, 'my.' + DOMAIN_0.domain),
mail.addDomain.bind(null, DOMAIN_0.domain)
], done);
}
......
......@@ -82,7 +82,6 @@ describe('updatechecker - box - manual (email)', function () {
cron.startJobs,
domains.add.bind(null, DOMAIN_0.domain, DOMAIN_0, AUDIT_SOURCE),
settings.setAdmin.bind(null, DOMAIN_0.domain, 'my.' + DOMAIN_0.domain),
mail.addDomain.bind(null, DOMAIN_0.domain),
users.createOwner.bind(null, USER_0.username, USER_0.password, USER_0.email, USER_0.displayName, AUDIT_SOURCE),
settings.setBoxAutoupdatePattern.bind(null, constants.AUTOUPDATE_PATTERN_NEVER),
settingsdb.set.bind(null, settings.CLOUDRON_TOKEN_KEY, 'atoken'),
......@@ -154,7 +153,6 @@ describe('updatechecker - box - automatic (no email)', function () {
cron.startJobs,
domains.add.bind(null, DOMAIN_0.domain, DOMAIN_0, AUDIT_SOURCE),
settings.setAdmin.bind(null, DOMAIN_0.domain, 'my.' + DOMAIN_0.domain),
mail.addDomain.bind(null, DOMAIN_0.domain),
users.createOwner.bind(null, USER_0.username, USER_0.password, USER_0.email, USER_0.displayName, AUDIT_SOURCE),
settingsdb.set.bind(null, settings.CLOUDRON_TOKEN_KEY, 'atoken'),
], done);
......@@ -190,7 +188,6 @@ describe('updatechecker - box - automatic free (email)', function () {
cron.startJobs,
domains.add.bind(null, DOMAIN_0.domain, DOMAIN_0, AUDIT_SOURCE),
settings.setAdmin.bind(null, DOMAIN_0.domain, 'my.' + DOMAIN_0.domain),
mail.addDomain.bind(null, DOMAIN_0.domain),
users.createOwner.bind(null, USER_0.username, USER_0.password, USER_0.email, USER_0.displayName, AUDIT_SOURCE),
settingsdb.set.bind(null, settings.CLOUDRON_TOKEN_KEY, 'atoken'),
], done);
......@@ -254,7 +251,6 @@ describe('updatechecker - app - manual (email)', function () {
cron.startJobs,
domains.add.bind(null, DOMAIN_0.domain, DOMAIN_0, AUDIT_SOURCE),
settings.setAdmin.bind(null, DOMAIN_0.domain, 'my.' + DOMAIN_0.domain),
mail.addDomain.bind(null, DOMAIN_0.domain),
users.createOwner.bind(null, USER_0.username, USER_0.password, USER_0.email, USER_0.displayName, AUDIT_SOURCE),
appdb.add.bind(null, APP_0.id, APP_0.appStoreId, APP_0.manifest, APP_0.location, APP_0.domain, apps._translatePortBindings(APP_0.portBindings, APP_0.manifest), APP_0),
settings.setAppAutoupdatePattern.bind(null, constants.AUTOUPDATE_PATTERN_NEVER),
......@@ -364,7 +360,6 @@ describe('updatechecker - app - automatic (no email)', function () {
cron.startJobs,
domains.add.bind(null, DOMAIN_0.domain, DOMAIN_0, AUDIT_SOURCE),
settings.setAdmin.bind(null, DOMAIN_0.domain, 'my.' + DOMAIN_0.domain),
mail.addDomain.bind(null, DOMAIN_0.domain),
users.createOwner.bind(null, USER_0.username, USER_0.password, USER_0.email, USER_0.displayName, AUDIT_SOURCE),
appdb.add.bind(null, APP_0.id, APP_0.appStoreId, APP_0.manifest, APP_0.location, APP_0.domain, apps._translatePortBindings(APP_0.portBindings, APP_0.manifest), APP_0),
settings.setAppAutoupdatePattern.bind(null, '00 00 1,3,5,23 * * *'),
......@@ -430,7 +425,6 @@ describe('updatechecker - app - automatic free (email)', function () {
cron.startJobs,
domains.add.bind(null, DOMAIN_0.domain, DOMAIN_0, AUDIT_SOURCE),
settings.setAdmin.bind(null, DOMAIN_0.domain, 'my.' + DOMAIN_0.domain),
mail.addDomain.bind(null, DOMAIN_0.domain),
users.createOwner.bind(null, USER_0.username, USER_0.password, USER_0.email, USER_0.displayName, AUDIT_SOURCE),
appdb.add.bind(null, APP_0.id, APP_0.appStoreId, APP_0.manifest, APP_0.location, APP_0.domain, apps._translatePortBindings(APP_0.portBindings, APP_0.manifest), APP_0),
settings.setAppAutoupdatePattern.bind(null, '00 00 1,3,5,23 * * *'),
......
......@@ -74,7 +74,6 @@ function setup(done) {
database._clear,
domains.add.bind(null, DOMAIN_0.domain, DOMAIN_0, AUDIT_SOURCE),
settings.setAdmin.bind(null, DOMAIN_0.domain, 'my.' + DOMAIN_0.domain),
mail.addDomain.bind(null, DOMAIN_0.domain),
], done);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment