diff --git a/src/cloudron.js b/src/cloudron.js index 7a06bb333..5ec87f96e 100644 --- a/src/cloudron.js +++ b/src/cloudron.js @@ -1,8 +1,6 @@ 'use strict'; exports = module.exports = { - CloudronError: CloudronError, - initialize: initialize, uninitialize: uninitialize, getConfig: getConfig, @@ -28,6 +26,7 @@ var apps = require('./apps.js'), async = require('async'), auditSource = require('./auditsource.js'), backups = require('./backups.js'), + BoxError = require('./boxerror.js'), clients = require('./clients.js'), constants = require('./constants.js'), cron = require('./cron.js'), @@ -52,37 +51,11 @@ var apps = require('./apps.js'), sysinfo = require('./sysinfo.js'), tasks = require('./tasks.js'), TaskError = require('./tasks.js').TaskError, - users = require('./users.js'), - util = require('util'); + users = require('./users.js'); var REBOOT_CMD = path.join(__dirname, 'scripts/reboot.sh'); -var NOOP_CALLBACK = function (error) { if (error) debug(error); }; - -function CloudronError(reason, errorOrMessage) { - assert.strictEqual(typeof reason, 'string'); - assert(errorOrMessage instanceof Error || typeof errorOrMessage === 'string' || typeof errorOrMessage === '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; - } -} -util.inherits(CloudronError, Error); -CloudronError.BAD_FIELD = 'Field error'; -CloudronError.INTERNAL_ERROR = 'Internal Error'; -CloudronError.EXTERNAL_ERROR = 'External Error'; -CloudronError.BAD_STATE = 'Bad state'; -CloudronError.ALREADY_UPTODATE = 'No Update Available'; +const NOOP_CALLBACK = function (error) { if (error) debug(error); }; function initialize(callback) { assert.strictEqual(typeof callback, 'function'); @@ -120,7 +93,7 @@ function notifyUpdate(callback) { if (version === constants.VERSION) return callback(); eventlog.add(eventlog.ACTION_UPDATE_FINISH, auditSource.CRON, { errorMessage: '', oldVersion: version || 'dev', newVersion: constants.VERSION }, function (error) { - if (error) return callback(new CloudronError(CloudronError.INTERNAL_ERROR, error)); + if (error) return callback(error); tasks.setCompletedByType(tasks.TASK_UPDATE, { error: null }, function (error) { if (error && error.reason !== TaskError.NOT_FOUND) return callback(error); // when hotfixing, task may not exist @@ -153,7 +126,7 @@ function getConfig(callback) { assert.strictEqual(typeof callback, 'function'); settings.getAll(function (error, allSettings) { - if (error) return callback(new CloudronError(CloudronError.INTERNAL_ERROR, error)); + if (error) return callback(error); // be picky about what we send out here since this is sent for 'normal' users as well callback(null, { @@ -251,7 +224,7 @@ function getLogs(unit, options, callback) { // need to handle box.log without subdir if (unit === 'box') args.push(path.join(paths.LOG_DIR, 'box.log')); else if (unit.startsWith('crash-')) args.push(path.join(paths.CRASH_LOG_DIR, unit.slice(6) + '.log')); - else return callback(new CloudronError(CloudronError.BAD_FIELD, 'No such unit')); + else return callback(new BoxError(BoxError.BAD_FIELD, 'No such unit', { field: 'unit' })); var cp = spawn('/usr/bin/tail', args); @@ -284,19 +257,19 @@ function prepareDashboardDomain(domain, auditSource, callback) { debug(`prepareDashboardDomain: ${domain}`); domains.get(domain, function (error, domainObject) { - if (error && error.reason === DomainsError.NOT_FOUND) return callback(new CloudronError(CloudronError.BAD_FIELD, 'No such domain')); - if (error) return callback(new CloudronError(CloudronError.INTERNAL_ERROR, error)); + if (error && error.reason === DomainsError.NOT_FOUND) return callback(new BoxError(BoxError.BAD_FIELD, 'No such domain', { field: 'domain' })); + if (error) return callback(new BoxError(BoxError.INTERNAL_ERROR, error)); const fqdn = domains.fqdn(constants.ADMIN_LOCATION, domainObject); apps.getAll(function (error, result) { - if (error) return callback(new CloudronError(CloudronError.INTERNAL_ERROR, error)); + if (error) return callback(new BoxError(BoxError.INTERNAL_ERROR, error)); const conflict = result.filter(app => app.fqdn === fqdn); - if (conflict.length) return callback(new CloudronError(CloudronError.BAD_STATE, 'Dashboard location conflicts with an existing app')); + if (conflict.length) return callback(new BoxError(BoxError.BAD_STATE, 'Dashboard location conflicts with an existing app')); tasks.add(tasks.TASK_PREPARE_DASHBOARD_DOMAIN, [ domain, auditSource ], function (error, taskId) { - if (error) return callback(new CloudronError(CloudronError.INTERNAL_ERROR, error)); + if (error) return callback(new BoxError(BoxError.INTERNAL_ERROR, error)); tasks.startTask(taskId, {}, NOOP_CALLBACK); @@ -315,11 +288,11 @@ function setDashboardDomain(domain, auditSource, callback) { debug(`setDashboardDomain: ${domain}`); domains.get(domain, function (error, domainObject) { - if (error && error.reason === DomainsError.NOT_FOUND) return callback(new CloudronError(CloudronError.BAD_FIELD, 'No such domain')); - if (error) return callback(new CloudronError(CloudronError.INTERNAL_ERROR, error)); + if (error && error.reason === DomainsError.NOT_FOUND) return callback(new BoxError(BoxError.BAD_FIELD, 'No such domain', { field: 'domain' })); + if (error) return callback(new BoxError(BoxError.INTERNAL_ERROR, error)); reverseProxy.writeAdminConfig(domain, function (error) { - if (error) return callback(new CloudronError(CloudronError.INTERNAL_ERROR, error)); + if (error) return callback(new BoxError(BoxError.INTERNAL_ERROR, error)); const fqdn = domains.fqdn(constants.ADMIN_LOCATION, domainObject); @@ -327,7 +300,7 @@ function setDashboardDomain(domain, auditSource, callback) { (done) => settings.setAdmin(domain, fqdn, done), (done) => clients.addDefaultClients(settings.adminOrigin(), done) ], function (error) { - if (error) return callback(new CloudronError(CloudronError.INTERNAL_ERROR, error)); + if (error) return callback(new BoxError(BoxError.INTERNAL_ERROR, error)); eventlog.add(eventlog.ACTION_DASHBOARD_DOMAIN_UPDATE, auditSource, { domain: domain, fqdn: fqdn }); @@ -371,7 +344,7 @@ function renewCerts(options, auditSource, callback) { assert.strictEqual(typeof callback, 'function'); tasks.add(tasks.TASK_RENEW_CERTS, [ options, auditSource ], function (error, taskId) { - if (error) return callback(new CloudronError(CloudronError.INTERNAL_ERROR, error)); + if (error) return callback(new BoxError(BoxError.INTERNAL_ERROR, error)); tasks.startTask(taskId, {}, NOOP_CALLBACK); diff --git a/src/routes/cloudron.js b/src/routes/cloudron.js index 2b20d3ca7..899f2105e 100644 --- a/src/routes/cloudron.js +++ b/src/routes/cloudron.js @@ -19,8 +19,8 @@ exports = module.exports = { let assert = require('assert'), async = require('async'), auditSource = require('../auditsource.js'), + BoxError = require('../boxerror.js'), cloudron = require('../cloudron.js'), - CloudronError = cloudron.CloudronError, custom = require('../custom.js'), disks = require('../disks.js'), externalldap = require('../externalldap.js'), @@ -30,6 +30,19 @@ let assert = require('assert'), updateChecker = require('../updatechecker.js'), UpdaterError = require('../updater.js').UpdaterError; +function toHttpError(error) { + switch (error.reason) { + case BoxError.NOT_FOUND: + return new HttpError(404, error); + case BoxError.BAD_STATE: + return new HttpError(409, error); + case BoxError.DATABASE_ERROR: + case BoxError.INTERNAL_ERROR: + default: + return new HttpError(500, error); + } +} + function reboot(req, res, next) { // Finish the request, to let the appstore know we triggered the reboot next(new HttpSuccess(202, {})); @@ -39,7 +52,7 @@ function reboot(req, res, next) { function isRebootRequired(req, res, next) { cloudron.isRebootRequired(function (error, result) { - if (error) return next(new HttpError(500, error)); + if (error) return next(toHttpError(error)); next(new HttpSuccess(200, { rebootRequired: result })); }); @@ -47,7 +60,7 @@ function isRebootRequired(req, res, next) { function getConfig(req, res, next) { cloudron.getConfig(function (error, cloudronConfig) { - if (error) return next(new HttpError(500, error)); + if (error) return next(toHttpError(error)); next(new HttpSuccess(200, cloudronConfig)); }); @@ -55,7 +68,7 @@ function getConfig(req, res, next) { function getDisks(req, res, next) { disks.getDisks(function (error, result) { - if (error) return next(new HttpError(500, error)); + if (error) return next(toHttpError(error)); next(new HttpSuccess(200, result)); }); @@ -103,8 +116,7 @@ function getLogs(req, res, next) { }; cloudron.getLogs(req.params.unit, options, function (error, logStream) { - if (error && error.reason === CloudronError.BAD_FIELD) return next(new HttpError(404, 'Invalid type')); - if (error) return next(new HttpError(500, error)); + if (error) return next(toHttpError(error)); res.writeHead(200, { 'Content-Type': 'application/x-logs', @@ -133,8 +145,7 @@ function getLogStream(req, res, next) { }; cloudron.getLogs(req.params.unit, options, function (error, logStream) { - if (error && error.reason === CloudronError.BAD_FIELD) return next(new HttpError(404, 'Invalid type')); - if (error) return next(new HttpError(500, error)); + if (error) return next(toHttpError(error)); res.writeHead(200, { 'Content-Type': 'text/event-stream', @@ -160,8 +171,7 @@ function setDashboardAndMailDomain(req, res, next) { if (!custom.spec().domains.changeDashboardDomain) return next(new HttpError(405, 'feature disabled by admin')); cloudron.setDashboardAndMailDomain(req.body.domain, auditSource.fromRequest(req), function (error) { - if (error && error.reason === CloudronError.BAD_FIELD) return next(new HttpError(404, error.message)); - if (error) return next(new HttpError(500, error)); + if (error) return next(toHttpError(error)); next(new HttpSuccess(204, {})); }); @@ -173,9 +183,7 @@ function prepareDashboardDomain(req, res, next) { if (!custom.spec().domains.changeDashboardDomain) return next(new HttpError(405, 'feature disabled by admin')); cloudron.prepareDashboardDomain(req.body.domain, auditSource.fromRequest(req), function (error, taskId) { - if (error && error.reason === CloudronError.BAD_FIELD) return next(new HttpError(404, error.message)); - if (error && error.reason === CloudronError.BAD_STATE) return next(new HttpError(409, error.message)); - if (error) return next(new HttpError(500, error)); + if (error) return next(toHttpError(error)); next(new HttpSuccess(202, { taskId })); }); @@ -183,8 +191,7 @@ function prepareDashboardDomain(req, res, next) { function renewCerts(req, res, next) { cloudron.renewCerts({ domain: req.body.domain || null }, auditSource.fromRequest(req), function (error, taskId) { - if (error && error.reason === CloudronError.NOT_FOUND) return next(new HttpError(404, error.message)); - if (error) return next(new HttpError(500, error)); + if (error) return next(toHttpError(error)); next(new HttpSuccess(202, { taskId })); });