Validate alternate domain
this also sets up fqdn in the eventlog entries
This commit is contained in:
88
src/apps.js
88
src/apps.js
@@ -365,12 +365,11 @@ function validateDataDir(dataDir) {
|
||||
return null;
|
||||
}
|
||||
|
||||
function getDuplicateErrorDetails(errorMessage, location, domainObject, portBindings, alternateDomains) {
|
||||
function getDuplicateErrorDetails(errorMessage, locations, domainObjectMap, portBindings) {
|
||||
assert.strictEqual(typeof errorMessage, 'string');
|
||||
assert.strictEqual(typeof location, 'string');
|
||||
assert.strictEqual(typeof domainObject, 'object');
|
||||
assert(Array.isArray(locations));
|
||||
assert.strictEqual(typeof domainObjectMap, 'object');
|
||||
assert.strictEqual(typeof portBindings, 'object');
|
||||
assert(Array.isArray(alternateDomains));
|
||||
|
||||
var match = errorMessage.match(/ER_DUP_ENTRY: Duplicate entry '(.*)' for key '(.*)'/);
|
||||
if (!match) {
|
||||
@@ -378,17 +377,13 @@ function getDuplicateErrorDetails(errorMessage, location, domainObject, portBind
|
||||
return new AppsError(AppsError.INTERNAL_ERROR, new Error(errorMessage));
|
||||
}
|
||||
|
||||
// check if the location or alternateDomains conflicts
|
||||
// check if a location conflicts
|
||||
if (match[2] === 'subdomain') {
|
||||
// mysql reports a unique conflict with a dash: eg. domain:example.com subdomain:test => test-example.com
|
||||
if (match[1] === `${location}-${domainObject.domain}`) {
|
||||
return new AppsError(AppsError.ALREADY_EXISTS, `Domain '${domains.fqdn(location, domainObject)}' is in use`, { location: location, domain: domainObject.domain });
|
||||
}
|
||||
for (let i = 0; i < locations.length; i++) {
|
||||
const { subdomain, domain } = locations[i];
|
||||
if (match[1] !== `${subdomain}-${domain}`) continue;
|
||||
|
||||
for (let d of alternateDomains) {
|
||||
if (match[1] !== `${d.subdomain}-${d.domain}`) continue;
|
||||
|
||||
return new AppsError(AppsError.ALREADY_EXISTS, `Alternate domain '${d.subdomain}.${d.domain}' is in use`, { location: d.subdomain, domain: d.domain });
|
||||
return new AppsError(AppsError.ALREADY_EXISTS, `Domain '${domains.fqdn(subdomain, domainObjectMap[domain])}' is in use`, { subdomain, domain });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -686,6 +681,24 @@ function checkAppState(app, state) {
|
||||
return null;
|
||||
}
|
||||
|
||||
function validateLocations(locations, callback) {
|
||||
assert(Array.isArray(locations));
|
||||
assert.strictEqual(typeof callback, 'function');
|
||||
|
||||
getDomainObjectMap(function (error, domainObjectMap) {
|
||||
if (error) return callback(error);
|
||||
|
||||
for (let location of locations) {
|
||||
if (!(location.domain in domainObjectMap)) return callback(new AppsError(AppsError.BAD_FIELD, 'No such domain', { field: 'location' }));
|
||||
|
||||
error = domains.validateHostname(location.subdomain, domainObjectMap[location.domain]);
|
||||
if (error) return callback(new AppsError(AppsError.BAD_FIELD, 'Bad location: ' + error.message, { field: 'location', location }));
|
||||
}
|
||||
|
||||
callback(null, domainObjectMap);
|
||||
});
|
||||
}
|
||||
|
||||
function install(data, user, auditSource, callback) {
|
||||
assert(data && typeof data === 'object');
|
||||
assert(user && typeof user === 'object');
|
||||
@@ -773,15 +786,12 @@ function install(data, user, auditSource, callback) {
|
||||
}
|
||||
}
|
||||
|
||||
domains.get(domain, function (error, domainObject) {
|
||||
if (error && error.reason === DomainsError.NOT_FOUND) return callback(new AppsError(AppsError.NOT_FOUND, 'No such domain'));
|
||||
if (error) return callback(new AppsError(AppsError.INTERNAL_ERROR, 'Could not get domain info:' + error.message));
|
||||
|
||||
error = domains.validateHostname(location, domainObject);
|
||||
if (error) return callback(new AppsError(AppsError.BAD_FIELD, 'Bad location: ' + error.message, { field: 'location' }));
|
||||
const locations = [{subdomain: location, domain}].concat(alternateDomains);
|
||||
validateLocations(locations, function (error, domainObjectMap) {
|
||||
if (error) return callback(error);
|
||||
|
||||
if (cert && key) {
|
||||
error = reverseProxy.validateCertificate(location, domainObject, { cert, key });
|
||||
error = reverseProxy.validateCertificate(location, domainObjectMap[domain], { cert, key });
|
||||
if (error) return callback(new AppsError(AppsError.BAD_FIELD, error.message, { field: 'cert' }));
|
||||
}
|
||||
|
||||
@@ -805,7 +815,7 @@ function install(data, user, auditSource, callback) {
|
||||
};
|
||||
|
||||
appdb.add(appId, appStoreId, manifest, location, domain, translatePortBindings(portBindings, manifest), data, function (error) {
|
||||
if (error && error.reason === DatabaseError.ALREADY_EXISTS) return callback(getDuplicateErrorDetails(error.message, location, domainObject, portBindings, data.alternateDomains));
|
||||
if (error && error.reason === DatabaseError.ALREADY_EXISTS) return callback(getDuplicateErrorDetails(error.message, locations, domainObjectMap, portBindings));
|
||||
if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new AppsError(AppsError.NOT_FOUND, error.message));
|
||||
if (error) return callback(new AppsError(AppsError.INTERNAL_ERROR, error));
|
||||
|
||||
@@ -814,7 +824,7 @@ function install(data, user, auditSource, callback) {
|
||||
|
||||
// save cert to boxdata/certs
|
||||
if (cert && key) {
|
||||
let error = reverseProxy.setAppCertificateSync(location, domainObject, { cert, key });
|
||||
let error = reverseProxy.setAppCertificateSync(location, domainObjectMap[domain], { cert, key });
|
||||
if (error) return callback(new AppsError(AppsError.INTERNAL_ERROR, 'Error setting cert: ' + error.message));
|
||||
}
|
||||
|
||||
@@ -828,7 +838,8 @@ function install(data, user, auditSource, callback) {
|
||||
addTask(appId, exports.ISTATE_PENDING_INSTALL, task, function (error, result) {
|
||||
if (error) return callback(error);
|
||||
|
||||
const newApp = _.extend({ fqdn: domains.fqdn(location, domainObject) }, data, { appStoreId, manifest, location, domain, portBindings });
|
||||
const newApp = _.extend({}, data, { appStoreId, manifest, location, domain, portBindings });
|
||||
postProcess(newApp, domainObjectMap);
|
||||
eventlog.add(eventlog.ACTION_APP_INSTALL, auditSource, { appId: appId, app: newApp, taskId: result.taskId });
|
||||
|
||||
callback(null, { id : appId, taskId: result.taskId });
|
||||
@@ -1177,20 +1188,17 @@ function setLocation(appId, data, auditSource, callback) {
|
||||
values.portBindings = translatePortBindings(data.portBindings || null, app.manifest);
|
||||
}
|
||||
|
||||
if ('alternateDomains' in data) {
|
||||
// TODO validate all subdomains [{ domain: '', subdomain: ''}]
|
||||
values.alternateDomains = data.alternateDomains;
|
||||
}
|
||||
|
||||
// move the mailbox name to match the new location
|
||||
if (app.mailboxName.endsWith('.app')) values.mailboxName = mailboxNameForLocation(values.location, app.manifest);
|
||||
|
||||
domains.get(values.domain, function (error, domainObject) {
|
||||
if (error && error.reason === DomainsError.NOT_FOUND) return callback(new AppsError(AppsError.NOT_FOUND, 'No such domain'));
|
||||
if (error) return callback(new AppsError(AppsError.INTERNAL_ERROR, 'Could not get domain info:' + error.message));
|
||||
if ('alternateDomains' in data) {
|
||||
values.alternateDomains = data.alternateDomains;
|
||||
}
|
||||
|
||||
error = domains.validateHostname(values.location, domainObject);
|
||||
if (error) return callback(new AppsError(AppsError.BAD_FIELD, 'Bad location: ' + error.message, { field: 'location' }));
|
||||
const locations = [{subdomain: values.location, domain: values.domain}].concat(values.alternateDomains);
|
||||
|
||||
validateLocations(locations, function (error, domainObjectMap) {
|
||||
if (error) return callback(error);
|
||||
|
||||
const task = {
|
||||
args: {
|
||||
@@ -1200,7 +1208,7 @@ function setLocation(appId, data, auditSource, callback) {
|
||||
values
|
||||
};
|
||||
addTask(appId, exports.ISTATE_PENDING_LOCATION_CHANGE, task, function (error, result) {
|
||||
if (error && error.reason === AppsError.ALREADY_EXISTS) error = getDuplicateErrorDetails(error.message, values.location, domainObject, data.portBindings, app.alternateDomains);
|
||||
if (error && error.reason === AppsError.ALREADY_EXISTS) error = getDuplicateErrorDetails(error.message, locations, domainObjectMap, data.portBindings);
|
||||
if (error) return callback(error);
|
||||
|
||||
eventlog.add(eventlog.ACTION_APP_CONFIGURE, auditSource, { appId: appId, app: app, location: values.location, domain: values.domain, portBindings: values.portBindings, alternateDomains: values.alternateDomains, taskId: result.taskId });
|
||||
@@ -1530,12 +1538,9 @@ function clone(appId, data, user, auditSource, callback) {
|
||||
mailboxName = mailboxNameForLocation(location, manifest);
|
||||
}
|
||||
|
||||
domains.get(domain, function (error, domainObject) {
|
||||
if (error && error.reason === DomainsError.NOT_FOUND) return callback(new AppsError(AppsError.EXTERNAL_ERROR, 'No such domain'));
|
||||
if (error) return callback(new AppsError(AppsError.INTERNAL_ERROR, 'Could not get domain info:' + error.message));
|
||||
|
||||
error = domains.validateHostname(location, domainObject);
|
||||
if (error) return callback(new AppsError(AppsError.BAD_FIELD, 'Bad location: ' + error.message));
|
||||
const locations = [{location, domain}];
|
||||
validateLocations(locations, function (error, domainObjectMap) {
|
||||
if (error) return callback(error);
|
||||
|
||||
var newAppId = uuid.v4();
|
||||
|
||||
@@ -1552,7 +1557,7 @@ function clone(appId, data, user, auditSource, callback) {
|
||||
};
|
||||
|
||||
appdb.add(newAppId, appStoreId, manifest, location, domain, translatePortBindings(portBindings, manifest), data, function (error) {
|
||||
if (error && error.reason === DatabaseError.ALREADY_EXISTS) return callback(getDuplicateErrorDetails(error.message, location, domainObject, portBindings, []));
|
||||
if (error && error.reason === DatabaseError.ALREADY_EXISTS) return callback(getDuplicateErrorDetails(error.message, locations, domainObjectMap, portBindings));
|
||||
if (error) return callback(new AppsError(AppsError.INTERNAL_ERROR, error));
|
||||
|
||||
purchaseApp({ appId: newAppId, appstoreId: app.appStoreId, manifestId: manifest.id }, function (error) {
|
||||
@@ -1568,6 +1573,7 @@ function clone(appId, data, user, auditSource, callback) {
|
||||
if (error) return callback(error);
|
||||
|
||||
const newApp = _.extend({}, data, { appStoreId, manifest, location, domain, portBindings });
|
||||
postProcess(newApp, domainObjectMap);
|
||||
eventlog.add(eventlog.ACTION_APP_CLONE, auditSource, { appId: newAppId, oldAppId: appId, backupId: backupId, oldApp: app, newApp: newApp, taskId: result.taskId });
|
||||
|
||||
callback(null, { id: newAppId, taskId: result.taskId });
|
||||
|
||||
Reference in New Issue
Block a user