Move AppsError to BoxError

This commit is contained in:
Girish Ramakrishnan
2019-10-24 10:39:47 -07:00
parent b078d37f37
commit bce1efb77c
5 changed files with 157 additions and 187 deletions
+133 -165
View File
@@ -1,8 +1,6 @@
'use strict';
exports = module.exports = {
AppsError: AppsError,
hasAccessTo: hasAccessTo,
removeInternalFields: removeInternalFields,
removeRestrictedFields: removeRestrictedFields,
@@ -138,38 +136,6 @@ var appdb = require('./appdb.js'),
validator = require('validator'),
_ = require('underscore');
// http://dustinsenos.com/articles/customErrorsInNode
// http://code.google.com/p/v8/wiki/JavaScriptStackTraceApi
function AppsError(reason, errorOrMessage, details) {
assert.strictEqual(typeof reason, 'string');
assert(errorOrMessage instanceof Error || typeof errorOrMessage === 'string' || typeof errorOrMessage === 'undefined');
assert(typeof details === 'object' || typeof details === 'undefined');
Error.call(this);
Error.captureStackTrace(this, this.constructor);
this.name = this.constructor.name;
this.reason = reason;
if (typeof errorOrMessage === 'undefined') {
this.message = reason;
} else if (typeof errorOrMessage === 'string') {
this.message = errorOrMessage;
} else {
this.message = 'Internal error';
this.nestedError = errorOrMessage;
}
this.details = details || {};
}
util.inherits(AppsError, Error);
AppsError.INTERNAL_ERROR = 'Internal Error';
AppsError.EXTERNAL_ERROR = 'External Error';
AppsError.ALREADY_EXISTS = 'Already Exists';
AppsError.NOT_FOUND = 'Not Found';
AppsError.BAD_FIELD = 'Bad Field';
AppsError.BAD_STATE = 'Bad State';
AppsError.PLAN_LIMIT = 'Plan Limit';
const NOOP_CALLBACK = function (error) { if (error) debug(error); };
// validate the port bindings
@@ -209,12 +175,12 @@ function validatePortBindings(portBindings, manifest) {
if (!portBindings) return null;
for (let portName in portBindings) {
if (!/^[a-zA-Z0-9_]+$/.test(portName)) return new AppsError(AppsError.BAD_FIELD, `${portName} is not a valid environment variable`, { field: 'portBindings', portName: portName });
if (!/^[a-zA-Z0-9_]+$/.test(portName)) return new BoxError(BoxError.BAD_FIELD, `${portName} is not a valid environment variable`, { field: 'portBindings', portName: portName });
const hostPort = portBindings[portName];
if (!Number.isInteger(hostPort)) return new AppsError(AppsError.BAD_FIELD, `${hostPort} is not an integer`, { field: 'portBindings', portName: portName });
if (RESERVED_PORTS.indexOf(hostPort) !== -1) return new AppsError(AppsError.BAD_FIELD, `Port ${hostPort} is reserved.`, { field: 'portBindings', portName: portName });
if (hostPort <= 1023 || hostPort > 65535) return new AppsError(AppsError.BAD_FIELD, `${hostPort} is not in permitted range`, { field: 'portBindings', portName: portName });
if (!Number.isInteger(hostPort)) return new BoxError(BoxError.BAD_FIELD, `${hostPort} is not an integer`, { field: 'portBindings', portName: portName });
if (RESERVED_PORTS.indexOf(hostPort) !== -1) return new BoxError(BoxError.BAD_FIELD, `Port ${hostPort} is reserved.`, { field: 'portBindings', portName: portName });
if (hostPort <= 1023 || hostPort > 65535) return new BoxError(BoxError.BAD_FIELD, `${hostPort} is not in permitted range`, { field: 'portBindings', portName: portName });
}
// it is OK if there is no 1-1 mapping between values in manifest.tcpPorts and portBindings. missing values implies
@@ -222,7 +188,7 @@ function validatePortBindings(portBindings, manifest) {
const tcpPorts = manifest.tcpPorts || { };
const udpPorts = manifest.udpPorts || { };
for (let portName in portBindings) {
if (!(portName in tcpPorts) && !(portName in udpPorts)) return new AppsError(AppsError.BAD_FIELD, `Invalid portBindings ${portName}`, { field: 'portBindings', portName: portName });
if (!(portName in tcpPorts) && !(portName in udpPorts)) return new BoxError(BoxError.BAD_FIELD, `Invalid portBindings ${portName}`, { field: 'portBindings', portName: portName });
}
return null;
@@ -250,13 +216,13 @@ function validateAccessRestriction(accessRestriction) {
if (accessRestriction === null) return null;
if (accessRestriction.users) {
if (!Array.isArray(accessRestriction.users)) return new AppsError(AppsError.BAD_FIELD, 'users array property required');
if (!accessRestriction.users.every(function (e) { return typeof e === 'string'; })) return new AppsError(AppsError.BAD_FIELD, 'All users have to be strings');
if (!Array.isArray(accessRestriction.users)) return new BoxError(BoxError.BAD_FIELD, 'users array property required');
if (!accessRestriction.users.every(function (e) { return typeof e === 'string'; })) return new BoxError(BoxError.BAD_FIELD, 'All users have to be strings');
}
if (accessRestriction.groups) {
if (!Array.isArray(accessRestriction.groups)) return new AppsError(AppsError.BAD_FIELD, 'groups array property required');
if (!accessRestriction.groups.every(function (e) { return typeof e === 'string'; })) return new AppsError(AppsError.BAD_FIELD, 'All groups have to be strings');
if (!Array.isArray(accessRestriction.groups)) return new BoxError(BoxError.BAD_FIELD, 'groups array property required');
if (!accessRestriction.groups.every(function (e) { return typeof e === 'string'; })) return new BoxError(BoxError.BAD_FIELD, 'All groups have to be strings');
}
// TODO: maybe validate if the users and groups actually exist
@@ -277,8 +243,8 @@ function validateMemoryLimit(manifest, memoryLimit) {
// a special value that indicates unlimited memory
if (memoryLimit === -1) return null;
if (memoryLimit < min) return new AppsError(AppsError.BAD_FIELD, 'memoryLimit too small');
if (memoryLimit > max) return new AppsError(AppsError.BAD_FIELD, 'memoryLimit too large');
if (memoryLimit < min) return new BoxError(BoxError.BAD_FIELD, 'memoryLimit too small');
if (memoryLimit > max) return new BoxError(BoxError.BAD_FIELD, 'memoryLimit too large');
return null;
}
@@ -287,8 +253,8 @@ function validateDebugMode(debugMode) {
assert.strictEqual(typeof debugMode, 'object');
if (debugMode === null) return null;
if ('cmd' in debugMode && debugMode.cmd !== null && !Array.isArray(debugMode.cmd)) return new AppsError(AppsError.BAD_FIELD, 'debugMode.cmd must be an array or null' );
if ('readonlyRootfs' in debugMode && typeof debugMode.readonlyRootfs !== 'boolean') return new AppsError(AppsError.BAD_FIELD, 'debugMode.readonlyRootfs must be a boolean' );
if ('cmd' in debugMode && debugMode.cmd !== null && !Array.isArray(debugMode.cmd)) return new BoxError(BoxError.BAD_FIELD, 'debugMode.cmd must be an array or null' );
if ('readonlyRootfs' in debugMode && typeof debugMode.readonlyRootfs !== 'boolean') return new BoxError(BoxError.BAD_FIELD, 'debugMode.readonlyRootfs must be a boolean' );
return null;
}
@@ -297,7 +263,7 @@ function validateRobotsTxt(robotsTxt) {
if (robotsTxt === null) return null;
// this is the nginx limit on inline strings. if we really hit this, we have to generate a file
if (robotsTxt.length > 4096) return new AppsError(AppsError.BAD_FIELD, 'robotsTxt must be less than 4096', { field: 'robotsTxt' });
if (robotsTxt.length > 4096) return new BoxError(BoxError.BAD_FIELD, 'robotsTxt must be less than 4096', { field: 'robotsTxt' });
// TODO: validate the robots file? we escape the string when templating the nginx config right now
@@ -307,9 +273,9 @@ function validateRobotsTxt(robotsTxt) {
function validateCsp(csp) {
if (csp === null) return null;
if (csp.length > 4096) return new AppsError(AppsError.BAD_FIELD, 'CSP must be less than 4096', { field: 'csp' });
if (csp.length > 4096) return new BoxError(BoxError.BAD_FIELD, 'CSP must be less than 4096', { field: 'csp' });
if (csp.includes('"')) return new AppsError(AppsError.BAD_FIELD, 'CSP cannot contains double quotes', { field: 'csp' });
if (csp.includes('"')) return new BoxError(BoxError.BAD_FIELD, 'CSP cannot contains double quotes', { field: 'csp' });
return null;
}
@@ -319,31 +285,31 @@ function validateBackupFormat(format) {
if (format === 'tgz' || format == 'rsync') return null;
return new AppsError(AppsError.BAD_FIELD, 'Invalid backup format');
return new BoxError(BoxError.BAD_FIELD, 'Invalid backup format');
}
function validateLabel(label) {
if (label === null) return null;
if (label.length > 128) return new AppsError(AppsError.BAD_FIELD, 'label must be less than 128', { field: 'label' });
if (label.length > 128) return new BoxError(BoxError.BAD_FIELD, 'label must be less than 128', { field: 'label' });
return null;
}
function validateTags(tags) {
if (tags.length > 64) return new AppsError(AppsError.BAD_FIELD, 'Can only set up to 64 tags', { field: 'tags' });
if (tags.length > 64) return new BoxError(BoxError.BAD_FIELD, 'Can only set up to 64 tags', { field: 'tags' });
if (tags.some(tag => tag.length == 0)) return new AppsError(AppsError.BAD_FIELD, 'tag cannot be empty', { field: 'tags' });
if (tags.some(tag => tag.length > 128)) return new AppsError(AppsError.BAD_FIELD, 'tag must be less than 128', { field: 'tags' });
if (tags.some(tag => tag.length == 0)) return new BoxError(BoxError.BAD_FIELD, 'tag cannot be empty', { field: 'tags' });
if (tags.some(tag => tag.length > 128)) return new BoxError(BoxError.BAD_FIELD, 'tag must be less than 128', { field: 'tags' });
return null;
}
function validateEnv(env) {
for (let key in env) {
if (key.length > 512) return new AppsError(AppsError.BAD_FIELD, 'Max env var key length is 512', { field: 'env', env: env });
if (key.length > 512) return new BoxError(BoxError.BAD_FIELD, 'Max env var key length is 512', { field: 'env', env: env });
// http://pubs.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap08.html
if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(key)) return new AppsError(AppsError.BAD_FIELD, `"${key}" is not a valid environment variable`, { field: 'env', env: env });
if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(key)) return new BoxError(BoxError.BAD_FIELD, `"${key}" is not a valid environment variable`, { field: 'env', env: env });
}
return null;
@@ -352,23 +318,23 @@ function validateEnv(env) {
function validateDataDir(dataDir) {
if (dataDir === null) return null;
if (path.resolve(dataDir) !== dataDir) return new AppsError(AppsError.BAD_FIELD, 'dataDir must be an absolute path', { field: 'dataDir' });
if (path.resolve(dataDir) !== dataDir) return new BoxError(BoxError.BAD_FIELD, 'dataDir must be an absolute path', { field: 'dataDir' });
// nfs shares will have the directory mounted already
let stat = safe.fs.lstatSync(dataDir);
if (stat) {
if (!stat.isDirectory()) return new AppsError(AppsError.BAD_FIELD, `dataDir ${dataDir} is not a directory`, { field: 'dataDir' });
if (!stat.isDirectory()) return new BoxError(BoxError.BAD_FIELD, `dataDir ${dataDir} is not a directory`, { field: 'dataDir' });
let entries = safe.fs.readdirSync(dataDir);
if (!entries) return new AppsError(AppsError.BAD_FIELD, `dataDir ${dataDir} could not be listed`, { field: 'dataDir' });
if (entries.length !== 0) return new AppsError(AppsError.BAD_FIELD, `dataDir ${dataDir} is not empty`, { field: 'dataDir' });
if (!entries) return new BoxError(BoxError.BAD_FIELD, `dataDir ${dataDir} could not be listed`, { field: 'dataDir' });
if (entries.length !== 0) return new BoxError(BoxError.BAD_FIELD, `dataDir ${dataDir} is not empty`, { field: 'dataDir' });
}
// backup logic relies on paths not overlapping (because it recurses)
if (dataDir.startsWith(paths.APPS_DATA_DIR)) return new AppsError(AppsError.BAD_FIELD, `dataDir ${dataDir} cannot be inside apps data`, { field: 'dataDir' });
if (dataDir.startsWith(paths.APPS_DATA_DIR)) return new BoxError(BoxError.BAD_FIELD, `dataDir ${dataDir} cannot be inside apps data`, { field: 'dataDir' });
// if we made it this far, it cannot start with any of these realistically
const fhs = [ '/bin', '/boot', '/etc', '/lib', '/lib32', '/lib64', '/proc', '/run', '/sbin', '/tmp', '/usr' ];
if (fhs.some((p) => dataDir.startsWith(p))) return new AppsError(AppsError.BAD_FIELD, `dataDir ${dataDir} cannot be placed inside this location`, { field: 'dataDir' });
if (fhs.some((p) => dataDir.startsWith(p))) return new BoxError(BoxError.BAD_FIELD, `dataDir ${dataDir} cannot be placed inside this location`, { field: 'dataDir' });
return null;
}
@@ -382,7 +348,7 @@ function getDuplicateErrorDetails(errorMessage, locations, domainObjectMap, port
var match = errorMessage.match(/ER_DUP_ENTRY: Duplicate entry '(.*)' for key '(.*)'/);
if (!match) {
debug('Unexpected SQL error message.', errorMessage);
return new AppsError(AppsError.INTERNAL_ERROR, new Error(errorMessage));
return new BoxError(BoxError.INTERNAL_ERROR, new Error(errorMessage));
}
// check if a location conflicts
@@ -391,20 +357,20 @@ function getDuplicateErrorDetails(errorMessage, locations, domainObjectMap, port
const { subdomain, domain } = locations[i];
if (match[1] !== `${subdomain}-${domain}`) continue;
return new AppsError(AppsError.ALREADY_EXISTS, `Domain '${domains.fqdn(subdomain, domainObjectMap[domain])}' is in use`, { subdomain, domain });
return new BoxError(BoxError.ALREADY_EXISTS, `Domain '${domains.fqdn(subdomain, domainObjectMap[domain])}' is in use`, { subdomain, domain });
}
}
// check if any of the port bindings conflict
for (let portName in portBindings) {
if (portBindings[portName] === parseInt(match[1])) return new AppsError(AppsError.ALREADY_EXISTS, `Port ${match[1]} is reserved`, { portName });
if (portBindings[portName] === parseInt(match[1])) return new BoxError(BoxError.ALREADY_EXISTS, `Port ${match[1]} is reserved`, { portName });
}
if (match[2] === 'dataDir') {
return new AppsError(AppsError.BAD_FIELD, `Data directory ${match[1]} is in use`, { field: 'dataDir' });
return new BoxError(BoxError.BAD_FIELD, `Data directory ${match[1]} is in use`, { field: 'dataDir' });
}
return new AppsError(AppsError.ALREADY_EXISTS, `${match[2]} '${match[1]}' is in use`);
return new BoxError(BoxError.ALREADY_EXISTS, `${match[2]} '${match[1]}' is in use`);
}
function getDataDir(app, dataDir) {
@@ -454,7 +420,7 @@ function getIconPath(appId, options, callback) {
const appstoreIconPath = `${paths.APP_ICONS_DIR}/${appId}.png`;
if (safe.fs.existsSync(appstoreIconPath)) return callback(null, appstoreIconPath);
callback(new AppsError(AppsError.NOT_FOUND, 'No icon'));
callback(new BoxError(BoxError.NOT_FOUND, 'No icon'));
}
function postProcess(app, domainObjectMap) {
@@ -492,7 +458,7 @@ function getDomainObjectMap(callback) {
assert.strictEqual(typeof callback, 'function');
domaindb.getAll(function (error, domainObjects) {
if (error) return callback(new AppsError(AppsError.INTERNAL_ERROR, error));
if (error) return callback(error);
let domainObjectMap = {};
for (let d of domainObjects) { domainObjectMap[d.domain] = d; }
@@ -509,8 +475,8 @@ function get(appId, callback) {
if (error) return callback(error);
appdb.get(appId, function (error, app) {
if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new AppsError(AppsError.NOT_FOUND, 'No such app'));
if (error) return callback(new AppsError(AppsError.INTERNAL_ERROR, error));
if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new BoxError(BoxError.NOT_FOUND, 'No such app'));
if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error));
postProcess(app, domainObjectMap);
@@ -527,8 +493,8 @@ function getByContainerId(containerId, callback) {
if (error) return callback(error);
appdb.getByContainerId(containerId, function (error, app) {
if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new AppsError(AppsError.NOT_FOUND, 'No such app'));
if (error) return callback(new AppsError(AppsError.INTERNAL_ERROR, error));
if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new BoxError(BoxError.NOT_FOUND, 'No such app'));
if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error));
postProcess(app, domainObjectMap);
@@ -546,13 +512,13 @@ function getByIpAddress(ip, callback) {
if (constants.TEST && exports._MOCK_GET_BY_IP_APP_ID) return get(exports._MOCK_GET_BY_IP_APP_ID, callback);
docker.getContainerIdByIp(ip, function (error, containerId) {
if (error) return callback(new AppsError(AppsError.INTERNAL_ERROR, error));
if (error) return callback(error);
docker.inspect(containerId, function (error, result) {
if (error) return callback(new AppsError(AppsError.INTERNAL_ERROR, error));
if (error) return callback(error);
const appId = safe.query(result, 'Config.Labels.appId', null);
if (!appId) return callback(new AppsError(AppsError.NOT_FOUND, 'No such app'));
if (!appId) return callback(new BoxError(BoxError.NOT_FOUND, 'No such app'));
get(appId, callback);
});
@@ -567,7 +533,7 @@ function getByFqdn(fqdn, callback) {
if (error) return callback(error);
var app = result.find(function (a) { return a.fqdn === fqdn; });
if (!app) return callback(new AppsError(AppsError.NOT_FOUND, 'No such app'));
if (!app) return callback(new BoxError(BoxError.NOT_FOUND, 'No such app'));
callback(null, app);
});
@@ -580,7 +546,7 @@ function getAll(callback) {
if (error) return callback(error);
appdb.getAll(function (error, apps) {
if (error) return callback(new AppsError(AppsError.INTERNAL_ERROR, error));
if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error));
apps.forEach((app) => postProcess(app, domainObjectMap));
@@ -603,7 +569,7 @@ function getAllByUser(user, callback) {
}
function downloadManifest(appStoreId, manifest, callback) {
if (!appStoreId && !manifest) return callback(new AppsError(AppsError.BAD_FIELD, 'Neither manifest nor appStoreId provided'));
if (!appStoreId && !manifest) return callback(new BoxError(BoxError.BAD_FIELD, 'Neither manifest nor appStoreId provided'));
if (!appStoreId) return callback(null, '', manifest);
@@ -614,9 +580,9 @@ function downloadManifest(appStoreId, manifest, callback) {
debug('downloading manifest from %s', url);
superagent.get(url).timeout(30 * 1000).end(function (error, result) {
if (error && !error.response) return callback(new AppsError(AppsError.EXTERNAL_ERROR, 'Network error downloading manifest:' + error.message));
if (error && !error.response) return callback(new BoxError(BoxError.EXTERNAL_ERROR, 'Network error downloading manifest:' + error.message));
if (result.statusCode !== 200) return callback(new AppsError(AppsError.NOT_FOUND, util.format('Failed to get app info from store.', result.statusCode, result.text)));
if (result.statusCode !== 200) return callback(new BoxError(BoxError.NOT_FOUND, util.format('Failed to get app info from store.', result.statusCode, result.text)));
callback(null, parts[0], result.body.manifest);
});
@@ -662,12 +628,12 @@ function addTask(appId, installationState, task, callback) {
const requireNullTaskId = 'requireNullTaskId' in task ? task.requireNullTaskId : true;
tasks.add(tasks.TASK_APP, [ appId, args ], function (error, taskId) {
if (error) return callback(new AppsError(AppsError.INTERNAL_ERROR, error));
if (error) return callback(error);
appdb.setTask(appId, _.extend({ installationState, taskId, error: null }, values), { requiredState, requireNullTaskId }, function (error) {
if (error && error.reason === DatabaseError.ALREADY_EXISTS) return callback(new AppsError(AppsError.ALREADY_EXISTS, error.message));
if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new AppsError(AppsError.BAD_STATE, 'Another task is scheduled for this app')); // could be because app went away OR a taskId exists
if (error) return callback(new AppsError(AppsError.INTERNAL_ERROR, error));
if (error && error.reason === DatabaseError.ALREADY_EXISTS) return callback(new BoxError(BoxError.ALREADY_EXISTS, error.message));
if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new BoxError(BoxError.BAD_STATE, 'Another task is scheduled for this app')); // could be because app went away OR a taskId exists
if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error));
if (scheduleNow) scheduleTask(appId, installationState, taskId, NOOP_CALLBACK);
@@ -680,10 +646,10 @@ function checkAppState(app, state) {
assert.strictEqual(typeof app, 'object');
assert.strictEqual(typeof state, 'string');
if (app.taskId) return new AppsError(AppsError.BAD_STATE, `Not allowed in this app state : ${app.installationState} / ${app.runState}`);
if (app.taskId) return new BoxError(BoxError.BAD_STATE, `Not allowed in this app state : ${app.installationState} / ${app.runState}`);
if (app.installationState === exports.ISTATE_ERROR) {
if (state !== exports.ISTATE_PENDING_UNINSTALL) return new AppsError(AppsError.BAD_STATE, 'Not allowed in error state');
if (state !== exports.ISTATE_PENDING_UNINSTALL) return new BoxError(BoxError.BAD_STATE, 'Not allowed in error state');
}
return null;
@@ -697,10 +663,10 @@ function validateLocations(locations, callback) {
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', domain: location.domain, subdomain: location.subdomain }));
if (!(location.domain in domainObjectMap)) return callback(new BoxError(BoxError.BAD_FIELD, 'No such domain', { field: 'location', domain: location.domain, subdomain: location.subdomain }));
error = domains.validateHostname(location.subdomain, domainObjectMap[location.domain]);
if (error) return callback(new AppsError(AppsError.BAD_FIELD, 'Bad location: ' + error.message, { field: 'location', domain: location.domain, subdomain: location.subdomain }));
if (error) return callback(new BoxError(BoxError.BAD_FIELD, 'Bad location: ' + error.message, { field: 'location', domain: location.domain, subdomain: location.subdomain }));
}
callback(null, domainObjectMap);
@@ -738,7 +704,7 @@ function install(data, user, auditSource, callback) {
if (error) return callback(error);
error = manifestFormat.parse(manifest);
if (error) return callback(new AppsError(AppsError.BAD_FIELD, 'Manifest error: ' + error.message));
if (error) return callback(new BoxError(BoxError.BAD_FIELD, 'Manifest error: ' + error.message));
error = checkManifestConstraints(manifest);
if (error) return callback(error);
@@ -761,7 +727,7 @@ function install(data, user, auditSource, callback) {
error = validateTags(tags);
if (error) return callback(error);
if ('sso' in data && !('optionalSso' in manifest)) return callback(new AppsError(AppsError.BAD_FIELD, 'sso can only be specified for apps with optionalSso'));
if ('sso' in data && !('optionalSso' in manifest)) return callback(new BoxError(BoxError.BAD_FIELD, 'sso can only be specified for apps with optionalSso'));
// if sso was unspecified, enable it by default if possible
if (sso === null) sso = !!manifest.addons['ldap'] || !!manifest.addons['oauth'];
@@ -770,7 +736,7 @@ function install(data, user, auditSource, callback) {
if (mailboxName) {
error = mail.validateName(mailboxName);
if (error) return callback(new AppsError(AppsError.BAD_FIELD, error.message, { field: 'mailboxName' }));
if (error) return callback(new BoxError(BoxError.BAD_FIELD, error.message, { field: 'mailboxName' }));
} else {
mailboxName = mailboxNameForLocation(location, manifest);
}
@@ -778,10 +744,10 @@ function install(data, user, auditSource, callback) {
var appId = uuid.v4();
if (icon) {
if (!validator.isBase64(icon)) return callback(new AppsError(AppsError.BAD_FIELD, 'icon is not base64', { field: 'icon' }));
if (!validator.isBase64(icon)) return callback(new BoxError(BoxError.BAD_FIELD, 'icon is not base64', { field: 'icon' }));
if (!safe.fs.writeFileSync(path.join(paths.APP_ICONS_DIR, appId + '.png'), Buffer.from(icon, 'base64'))) {
return callback(new AppsError(AppsError.INTERNAL_ERROR, 'Error saving icon:' + safe.error.message));
return callback(new BoxError(BoxError.FS_ERROR, 'Error saving icon:' + safe.error.message));
}
}
@@ -791,7 +757,7 @@ function install(data, user, auditSource, callback) {
if (cert && key) {
error = reverseProxy.validateCertificate(location, domainObjectMap[domain], { cert, key });
if (error) return callback(new AppsError(AppsError.BAD_FIELD, error.message, { field: 'cert' }));
if (error) return callback(new BoxError(BoxError.BAD_FIELD, error.message, { field: 'cert' }));
}
debug('Will install app with id : ' + appId);
@@ -814,8 +780,8 @@ 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, 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));
if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new BoxError(BoxError.NOT_FOUND, error.message));
if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error));
purchaseApp({ appId: appId, appstoreId: appStoreId, manifestId: manifest.id }, function (error) {
if (error) return callback(error);
@@ -823,7 +789,7 @@ function install(data, user, auditSource, callback) {
// save cert to boxdata/certs
if (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));
if (error) return callback(error);
}
const task = {
@@ -862,8 +828,8 @@ function setAccessRestriction(appId, accessRestriction, auditSource, callback) {
if (error) return callback(error);
appdb.update(appId, { accessRestriction: accessRestriction }, function (error) {
if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new AppsError(AppsError.NOT_FOUND, 'No such app'));
if (error) return callback(new AppsError(AppsError.INTERNAL_ERROR, error));
if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new BoxError(BoxError.NOT_FOUND, 'No such app'));
if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error));
eventlog.add(eventlog.ACTION_APP_CONFIGURE, auditSource, { appId: appId, app: app, accessRestriction: accessRestriction });
@@ -885,8 +851,8 @@ function setLabel(appId, label, auditSource, callback) {
if (error) return callback(error);
appdb.update(appId, { label: label }, function (error) {
if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new AppsError(AppsError.NOT_FOUND, 'No such app'));
if (error) return callback(new AppsError(AppsError.INTERNAL_ERROR, error));
if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new BoxError(BoxError.NOT_FOUND, 'No such app'));
if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error));
eventlog.add(eventlog.ACTION_APP_CONFIGURE, auditSource, { appId: appId, app: app, label: label });
@@ -908,8 +874,8 @@ function setTags(appId, tags, auditSource, callback) {
if (error) return callback(error);
appdb.update(appId, { tags: tags }, function (error) {
if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new AppsError(AppsError.NOT_FOUND, 'No such app'));
if (error) return callback(new AppsError(AppsError.INTERNAL_ERROR, error));
if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new BoxError(BoxError.NOT_FOUND, 'No such app'));
if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error));
eventlog.add(eventlog.ACTION_APP_CONFIGURE, auditSource, { appId: appId, app: app, tags: tags });
@@ -928,10 +894,10 @@ function setIcon(appId, icon, auditSource, callback) {
if (error) return callback(error);
if (icon) {
if (!validator.isBase64(icon)) return callback(new AppsError(AppsError.BAD_FIELD, 'icon is not base64', { field: 'icon' }));
if (!validator.isBase64(icon)) return callback(new BoxError(BoxError.BAD_FIELD, 'icon is not base64', { field: 'icon' }));
if (!safe.fs.writeFileSync(path.join(paths.APP_ICONS_DIR, appId + '.user.png'), Buffer.from(icon, 'base64'))) {
return callback(new AppsError(AppsError.INTERNAL_ERROR, 'Error saving icon:' + safe.error.message));
return callback(new BoxError(BoxError.FS_ERROR, 'Error saving icon:' + safe.error.message));
}
} else {
safe.fs.unlinkSync(path.join(paths.APP_ICONS_DIR, appId + '.user.png'));
@@ -1044,7 +1010,7 @@ function setMailbox(appId, mailboxName, auditSource, callback) {
if (mailboxName) {
error = mail.validateName(mailboxName);
if (error) return callback(new AppsError(AppsError.BAD_FIELD, error.message, { field: 'mailboxName' }));
if (error) return callback(new BoxError(BoxError.BAD_FIELD, error.message, { field: 'mailboxName' }));
} else {
mailboxName = mailboxNameForLocation(app.location, app.manifest);
}
@@ -1073,8 +1039,8 @@ function setAutomaticBackup(appId, enable, auditSource, callback) {
if (error) return callback(error);
appdb.update(appId, { enableBackup: enable }, function (error) {
if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new AppsError(AppsError.NOT_FOUND, 'No such app'));
if (error) return callback(new AppsError(AppsError.INTERNAL_ERROR, error));
if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new BoxError(BoxError.NOT_FOUND, 'No such app'));
if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error));
eventlog.add(eventlog.ACTION_APP_CONFIGURE, auditSource, { appId: appId, app: app, enableBackup: enable });
@@ -1093,8 +1059,8 @@ function setAutomaticUpdate(appId, enable, auditSource, callback) {
if (error) return callback(error);
appdb.update(appId, { enableAutomaticUpdate: enable }, function (error) {
if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new AppsError(AppsError.NOT_FOUND, 'No such app'));
if (error) return callback(new AppsError(AppsError.INTERNAL_ERROR, error));
if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new BoxError(BoxError.NOT_FOUND, 'No such app'));
if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error));
eventlog.add(eventlog.ACTION_APP_CONFIGURE, auditSource, { appId: appId, app: app, enableAutomaticUpdate: enable });
@@ -1121,11 +1087,11 @@ function setReverseProxyConfig(appId, reverseProxyConfig, auditSource, callback)
if (error) return callback(error);
reverseProxy.writeAppConfig(_.extend({}, app, { reverseProxyConfig }), function (error) {
if (error) return callback(new AppsError(AppsError.EXTERNAL_ERROR, 'Error writing nginx config'));
if (error) return callback(error);
appdb.update(appId, { reverseProxyConfig }, function (error) {
if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new AppsError(AppsError.NOT_FOUND, 'No such app'));
if (error) return callback(new AppsError(AppsError.INTERNAL_ERROR, error));
if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new BoxError(BoxError.NOT_FOUND, 'No such app'));
if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error));
eventlog.add(eventlog.ACTION_APP_CONFIGURE, auditSource, { appId, app, reverseProxyConfig });
@@ -1145,16 +1111,16 @@ function setCertificate(appId, bundle, auditSource, callback) {
if (error) return callback(error);
domains.get(app.domain, function (error, domainObject) {
if (error && error.reason === BoxError.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 (error && error.reason === BoxError.NOT_FOUND) return callback(new BoxError(BoxError.NOT_FOUND, 'No such domain'));
if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, 'Could not get domain info:' + error.message));
if (bundle.cert && bundle.key) {
error = reverseProxy.validateCertificate(app.location, domainObject, { cert: bundle.cert, key: bundle.key });
if (error) return callback(new AppsError(AppsError.BAD_FIELD, error.message, { field: 'cert' }));
if (error) return callback(new BoxError(BoxError.BAD_FIELD, error.message, { field: 'cert' }));
}
error = reverseProxy.setAppCertificateSync(app.location, domainObject, { cert: bundle.cert, key: bundle.key });
if (error) return callback(new AppsError(AppsError.INTERNAL_ERROR, 'Error setting cert: ' + error.message));
if (error) return callback(error);
eventlog.add(eventlog.ACTION_APP_CONFIGURE, auditSource, { appId: appId, app: app, cert: bundle.cert, key: bundle.key });
@@ -1210,7 +1176,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, locations, domainObjectMap, data.portBindings);
if (error && error.reason === BoxError.ALREADY_EXISTS) error = getDuplicateErrorDetails(error.message, locations, domainObjectMap, data.portBindings);
if (error) return callback(error);
values.fqdn = domains.fqdn(values.location, domainObjectMap[values.domain]);
@@ -1273,7 +1239,7 @@ function update(appId, data, auditSource, callback) {
if (error) return callback(error);
error = manifestFormat.parse(manifest);
if (error) return callback(new AppsError(AppsError.BAD_FIELD, 'Manifest error:' + error.message));
if (error) return callback(new BoxError(BoxError.BAD_FIELD, 'Manifest error:' + error.message));
error = checkManifestConstraints(manifest);
if (error) return callback(error);
@@ -1283,7 +1249,7 @@ function update(appId, data, auditSource, callback) {
// prevent user from installing a app with different manifest id over an existing app
// this allows cloudron install -f --app <appid> for an app installed from the appStore
if (app.manifest.id !== updateConfig.manifest.id) {
if (!data.force) return callback(new AppsError(AppsError.BAD_FIELD, 'manifest id does not match. force to override'));
if (!data.force) return callback(new BoxError(BoxError.BAD_FIELD, 'manifest id does not match. force to override'));
// clear appStoreId so that this app does not get updates anymore
updateConfig.appStoreId = '';
}
@@ -1292,15 +1258,15 @@ function update(appId, data, auditSource, callback) {
const currentVersion = semver.prerelease(app.manifest.version) ? app.manifest.version : `${app.manifest.version}-0`;
const updateVersion = semver.prerelease(updateConfig.manifest.version) ? updateConfig.manifest.version : `${updateConfig.manifest.version}-0`;
if (app.appStoreId !== '' && semver.lte(updateVersion, currentVersion)) {
if (!data.force) return callback(new AppsError(AppsError.BAD_FIELD, 'Downgrades are not permitted for apps installed from AppStore. force to override'));
if (!data.force) return callback(new BoxError(BoxError.BAD_FIELD, 'Downgrades are not permitted for apps installed from AppStore. force to override'));
}
if ('icon' in data) {
if (data.icon) {
if (!validator.isBase64(data.icon)) return callback(new AppsError(AppsError.BAD_FIELD, 'icon is not base64', { field: 'icon' }));
if (!validator.isBase64(data.icon)) return callback(new BoxError(BoxError.BAD_FIELD, 'icon is not base64', { field: 'icon' }));
if (!safe.fs.writeFileSync(path.join(paths.APP_ICONS_DIR, appId + '.user.png'), Buffer.from(data.icon, 'base64'))) {
return callback(new AppsError(AppsError.INTERNAL_ERROR, 'Error saving icon:' + safe.error.message));
return callback(new BoxError(BoxError.FS_ERROR, 'Error saving icon:' + safe.error.message));
}
} else {
safe.fs.unlinkSync(path.join(paths.APP_ICONS_DIR, appId + '.user.png'));
@@ -1308,7 +1274,7 @@ function update(appId, data, auditSource, callback) {
}
// do not update apps in debug mode
if (app.debugMode && !data.force) return callback(new AppsError(AppsError.BAD_STATE, 'debug mode enabled. force to override'));
if (app.debugMode && !data.force) return callback(new BoxError(BoxError.BAD_STATE, 'debug mode enabled. force to override'));
// Ensure we update the memory limit in case the new app requires more memory as a minimum
// 0 and -1 are special updateConfig for memory limit indicating unset and unlimited
@@ -1420,7 +1386,7 @@ function repair(appId, data, auditSource, callback) {
// create a new task instead of updating the old one, since it helps tracking
addTask(appId, newState, { args, values, requiredState: null }, function (error, result) {
if (error && error.reason === AppsError.ALREADY_EXISTS) error = getDuplicateErrorDetails(error.message, locations, domainObjectMap, { /* portBindings */});
if (error && error.reason === BoxError.ALREADY_EXISTS) error = getDuplicateErrorDetails(error.message, locations, domainObjectMap, { /* portBindings */});
if (error) return callback(error);
eventlog.add(eventlog.ACTION_APP_REPAIR, auditSource, { taskId: result.taskId, app, newState });
@@ -1450,11 +1416,11 @@ function restore(appId, data, auditSource, callback) {
var func = data.backupId ? backups.get.bind(null, data.backupId) : function (next) { return next(null, { manifest: app.manifest }); };
func(function (error, backupInfo) {
if (error && error.reason === BoxError.NOT_FOUND) return callback(new AppsError(AppsError.EXTERNAL_ERROR, error.message));
if (error && error.reason === BoxError.EXTERNAL_ERROR) return callback(new AppsError(AppsError.EXTERNAL_ERROR, error.message));
if (error) return callback(new AppsError(AppsError.INTERNAL_ERROR, error));
if (error && error.reason === BoxError.NOT_FOUND) return callback(new BoxError(BoxError.EXTERNAL_ERROR, error.message));
if (error && error.reason === BoxError.EXTERNAL_ERROR) return callback(new BoxError(BoxError.EXTERNAL_ERROR, error.message));
if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error));
if (!backupInfo.manifest) callback(new AppsError(AppsError.EXTERNAL_ERROR, 'Could not get restore manifest'));
if (!backupInfo.manifest) callback(new BoxError(BoxError.EXTERNAL_ERROR, 'Could not get restore manifest'));
// re-validate because this new box version may not accept old configs
error = checkManifestConstraints(backupInfo.manifest);
@@ -1530,14 +1496,14 @@ function purchaseApp(data, callback) {
appdb.del(data.appId, function (delError) {
if (delError) debug('install: Failed to rollback app installation.', delError);
if (error.reason === AppstoreError.NOT_FOUND) return callback(new AppsError(AppsError.NOT_FOUND, error.message));
if (error && error.reason === AppstoreError.PLAN_LIMIT) return callback(new AppsError(AppsError.PLAN_LIMIT, error.message));
if (error && error.reason === AppstoreError.INVALID_TOKEN) return callback(new AppsError(AppsError.EXTERNAL_ERROR, error.message));
if (error && error.reason === AppstoreError.LICENSE_ERROR) return callback(new AppsError(AppsError.EXTERNAL_ERROR, error.message));
if (error && error.reason === AppstoreError.NOT_REGISTERED) return callback(new AppsError(AppsError.EXTERNAL_ERROR, error.message));
if (error && error.reason === AppstoreError.EXTERNAL_ERROR) return callback(new AppsError(AppsError.EXTERNAL_ERROR, error.message));
if (error.reason === AppstoreError.NOT_FOUND) return callback(new BoxError(BoxError.NOT_FOUND, error.message));
if (error && error.reason === AppstoreError.PLAN_LIMIT) return callback(new BoxError(BoxError.PLAN_LIMIT, error.message));
if (error && error.reason === AppstoreError.INVALID_TOKEN) return callback(new BoxError(BoxError.EXTERNAL_ERROR, error.message));
if (error && error.reason === AppstoreError.LICENSE_ERROR) return callback(new BoxError(BoxError.EXTERNAL_ERROR, error.message));
if (error && error.reason === AppstoreError.NOT_REGISTERED) return callback(new BoxError(BoxError.EXTERNAL_ERROR, error.message));
if (error && error.reason === AppstoreError.EXTERNAL_ERROR) return callback(new BoxError(BoxError.EXTERNAL_ERROR, error.message));
callback(new AppsError(AppsError.INTERNAL_ERROR, error));
callback(new BoxError(BoxError.DATABASE_ERROR, error));
});
});
}
@@ -1567,11 +1533,11 @@ function clone(appId, data, user, auditSource, callback) {
if (error) return callback(error);
backups.get(backupId, function (error, backupInfo) {
if (error && error.reason === BoxError.EXTERNAL_ERROR) return callback(new AppsError(AppsError.EXTERNAL_ERROR, error.message));
if (error && error.reason === BoxError.NOT_FOUND) return callback(new AppsError(AppsError.EXTERNAL_ERROR, 'Backup not found'));
if (error) return callback(new AppsError(AppsError.INTERNAL_ERROR, error));
if (error && error.reason === BoxError.EXTERNAL_ERROR) return callback(new BoxError(BoxError.EXTERNAL_ERROR, error.message));
if (error && error.reason === BoxError.NOT_FOUND) return callback(new BoxError(BoxError.EXTERNAL_ERROR, 'Backup not found'));
if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error));
if (!backupInfo.manifest) callback(new AppsError(AppsError.EXTERNAL_ERROR, 'Could not get restore config'));
if (!backupInfo.manifest) callback(new BoxError(BoxError.EXTERNAL_ERROR, 'Could not get restore config'));
const manifest = backupInfo.manifest, appStoreId = app.appStoreId;
@@ -1584,7 +1550,7 @@ function clone(appId, data, user, auditSource, callback) {
if (mailboxName) {
error = mail.validateName(mailboxName);
if (error) return callback(new AppsError(AppsError.BAD_FIELD, error.message, { field: 'mailboxName' }));
if (error) return callback(new BoxError(BoxError.BAD_FIELD, error.message, { field: 'mailboxName' }));
} else {
mailboxName = mailboxNameForLocation(location, manifest);
}
@@ -1610,7 +1576,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, locations, domainObjectMap, portBindings));
if (error) return callback(new AppsError(AppsError.INTERNAL_ERROR, error));
if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error));
purchaseApp({ appId: newAppId, appstoreId: app.appStoreId, manifestId: manifest.id }, function (error) {
if (error) return callback(error);
@@ -1652,11 +1618,11 @@ function uninstall(appId, auditSource, callback) {
if (error) return callback(error);
appstore.unpurchaseApp(appId, { appstoreId: app.appStoreId, manifestId: app.manifest.id }, function (error) {
if (error && error.reason === AppstoreError.NOT_FOUND) return callback(new AppsError(AppsError.NOT_FOUND));
if (error && error.reason === AppstoreError.INVALID_TOKEN) return callback(new AppsError(AppsError.EXTERNAL_ERROR, error.message));
if (error && error.reason === AppstoreError.LICENSE_ERROR) return callback(new AppsError(AppsError.EXTERNAL_ERROR, error.message));
if (error && error.reason === AppstoreError.EXTERNAL_ERROR) return callback(new AppsError(AppsError.EXTERNAL_ERROR, error.message));
if (error) return callback(new AppsError(AppsError.INTERNAL_ERROR, error));
if (error && error.reason === AppstoreError.NOT_FOUND) return callback(new BoxError(BoxError.NOT_FOUND));
if (error && error.reason === AppstoreError.INVALID_TOKEN) return callback(new BoxError(BoxError.EXTERNAL_ERROR, error.message));
if (error && error.reason === AppstoreError.LICENSE_ERROR) return callback(new BoxError(BoxError.EXTERNAL_ERROR, error.message));
if (error && error.reason === AppstoreError.EXTERNAL_ERROR) return callback(new BoxError(BoxError.EXTERNAL_ERROR, error.message));
if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error));
const task = {
args: {},
@@ -1725,16 +1691,16 @@ function stop(appId, callback) {
function checkManifestConstraints(manifest) {
assert(manifest && typeof manifest === 'object');
if (manifest.manifestVersion > 2) return new AppsError(AppsError.BAD_FIELD, 'Manifest version must be <= 2');
if (manifest.manifestVersion > 2) return new BoxError(BoxError.BAD_FIELD, 'Manifest version must be <= 2');
if (!manifest.dockerImage) return new AppsError(AppsError.BAD_FIELD, 'Missing dockerImage'); // dockerImage is optional in manifest
if (!manifest.dockerImage) return new BoxError(BoxError.BAD_FIELD, 'Missing dockerImage'); // dockerImage is optional in manifest
if (semver.valid(manifest.maxBoxVersion) && semver.gt(constants.VERSION, manifest.maxBoxVersion)) {
return new AppsError(AppsError.BAD_FIELD, 'Box version exceeds Apps maxBoxVersion');
return new BoxError(BoxError.BAD_FIELD, 'Box version exceeds Apps maxBoxVersion');
}
if (semver.valid(manifest.minBoxVersion) && semver.gt(manifest.minBoxVersion, constants.VERSION)) {
return new AppsError(AppsError.BAD_FIELD, 'App version requires a new platform version');
return new BoxError(BoxError.BAD_FIELD, 'App version requires a new platform version');
}
return null;
@@ -1752,7 +1718,7 @@ function exec(appId, options, callback) {
if (error) return callback(error);
if (app.installationState !== exports.ISTATE_INSTALLED || app.runState !== exports.RSTATE_RUNNING) {
return callback(new AppsError(AppsError.BAD_STATE, 'App not installed or running'));
return callback(new BoxError(BoxError.BAD_STATE, 'App not installed or running'));
}
var container = docker.connection.getContainer(app.containerId);
@@ -1770,9 +1736,9 @@ function exec(appId, options, callback) {
};
container.exec(execOptions, function (error, exec) {
if (error && error.statusCode === 409) return callback(new AppsError(AppsError.BAD_STATE, error.message)); // container restarting/not running
if (error && error.statusCode === 409) return callback(new BoxError(BoxError.BAD_STATE, error.message)); // container restarting/not running
if (error) return callback(error);
if (error) return callback(new AppsError(AppsError.INTERNAL_ERROR, error));
var startOptions = {
Detach: false,
Tty: options.tty,
@@ -1788,7 +1754,7 @@ function exec(appId, options, callback) {
stderr: true
};
exec.start(startOptions, function(error, stream /* in hijacked mode, this is a net.socket */) {
if (error) return callback(new AppsError(AppsError.INTERNAL_ERROR, error));
if (error) return callback(error);
if (options.rows && options.columns) {
// there is a race where resizing too early results in a 404 "no such exec"
@@ -1884,11 +1850,11 @@ function listBackups(page, perPage, appId, callback) {
assert.strictEqual(typeof callback, 'function');
appdb.exists(appId, function (error, exists) {
if (error) return callback(new AppsError(AppsError.INTERNAL_ERROR, error));
if (!exists) return callback(new AppsError(AppsError.NOT_FOUND));
if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error));
if (!exists) return callback(new BoxError(BoxError.NOT_FOUND));
backups.getByAppIdPaged(page, perPage, appId, function (error, results) {
if (error) return callback(new AppsError(AppsError.INTERNAL_ERROR, error));
if (error) return callback(error);
callback(null, results);
});
@@ -1899,7 +1865,8 @@ function restoreInstalledApps(callback) {
assert.strictEqual(typeof callback, 'function');
getAll(function (error, apps) {
if (error) return callback(new AppsError(AppsError.INTERNAL_ERROR, error));
if (error) return callback(error);
apps = apps.filter(app => app.installationState !== exports.ISTATE_ERROR); // remove errored apps. let them be 'repaired' by hand
apps = apps.filter(app => app.installationState !== exports.ISTATE_PENDING_RESTORE); // safeguard against tasks being created non-stop if we crash on startup
@@ -1938,7 +1905,8 @@ function configureInstalledApps(callback) {
assert.strictEqual(typeof callback, 'function');
getAll(function (error, apps) {
if (error) return callback(new AppsError(AppsError.INTERNAL_ERROR, error));
if (error) return callback(error);
apps = apps.filter(app => app.installationState !== exports.ISTATE_ERROR); // remove errored apps. let them be 'repaired' by hand
apps = apps.filter(app => app.installationState !== exports.ISTATE_PENDING_CONFIGURE); // safeguard against tasks being created non-stop if we crash on startup
@@ -1998,7 +1966,7 @@ function downloadFile(appId, filePath, callback) {
stream.on('data', function (d) { data += d; });
stream.on('end', function () {
var parts = data.split('-');
if (parts.length !== 2) return callback(new AppsError(AppsError.NOT_FOUND, 'file does not exist'));
if (parts.length !== 2) return callback(new BoxError(BoxError.NOT_FOUND, 'file does not exist'));
var type = parts[0], filename, cmd, size;
@@ -2006,13 +1974,13 @@ function downloadFile(appId, filePath, callback) {
cmd = [ 'cat', filePath ];
size = parseInt(parts[1], 10);
filename = path.basename(filePath);
if (isNaN(size)) return callback(new AppsError(AppsError.NOT_FOUND, 'file does not exist'));
if (isNaN(size)) return callback(new BoxError(BoxError.NOT_FOUND, 'file does not exist'));
} else if (type === 'directory') {
cmd = ['tar', 'zcf', '-', '-C', filePath, '.'];
filename = path.basename(filePath) + '.tar.gz';
size = 0; // unknown
} else {
return callback(new AppsError(AppsError.NOT_FOUND, 'only files or dirs can be downloaded'));
return callback(new BoxError(BoxError.NOT_FOUND, 'only files or dirs can be downloaded'));
}
exec(appId, { cmd: cmd , tty: false }, function (error, stream) {