diff --git a/src/boxerror.js b/src/boxerror.js index f08612b82..41dfab9aa 100644 --- a/src/boxerror.js +++ b/src/boxerror.js @@ -40,13 +40,14 @@ BoxError.CONFLICT = 'Conflict'; BoxError.DATABASE_ERROR = 'Database Error'; BoxError.DNS_ERROR = 'DNS Error'; BoxError.DOCKER_ERROR = 'Docker Error'; -BoxError.EXTERNAL_ERROR = 'External Error'; +BoxError.EXTERNAL_ERROR = 'External Error'; // use this for external API errors BoxError.FS_ERROR = 'FileSystem Error'; BoxError.INTERNAL_ERROR = 'Internal Error'; BoxError.LOGROTATE_ERROR = 'Logrotate Error'; BoxError.NETWORK_ERROR = 'Network Error'; BoxError.NGINX_ERROR = 'Nginx Error'; BoxError.NOT_FOUND = 'Not found'; +BoxError.NOT_SIGNED = 'Not Signed'; BoxError.OPENSSL_ERROR = 'OpenSSL Error'; BoxError.REVERSEPROXY_ERROR = 'ReverseProxy Error'; BoxError.TASK_ERROR = 'Task Error'; diff --git a/src/routes/cloudron.js b/src/routes/cloudron.js index 899f2105e..2a6521e81 100644 --- a/src/routes/cloudron.js +++ b/src/routes/cloudron.js @@ -27,8 +27,7 @@ let assert = require('assert'), HttpError = require('connect-lastmile').HttpError, HttpSuccess = require('connect-lastmile').HttpSuccess, updater = require('../updater.js'), - updateChecker = require('../updatechecker.js'), - UpdaterError = require('../updater.js').UpdaterError; + updateChecker = require('../updatechecker.js'); function toHttpError(error) { switch (error.reason) { @@ -79,8 +78,8 @@ function update(req, res, next) { // this only initiates the update, progress can be checked via the progress route updater.updateToLatest(req.body, auditSource.fromRequest(req), function (error, taskId) { - if (error && error.reason === UpdaterError.ALREADY_UPTODATE) return next(new HttpError(422, error.message)); - if (error && error.reason === UpdaterError.BAD_STATE) return next(new HttpError(409, error.message)); + if (error && error.reason === BoxError.NOT_FOUND) return next(new HttpError(422, error.message)); + if (error && error.reason === BoxError.BAD_STATE) return next(new HttpError(409, error.message)); if (error) return next(new HttpError(500, error)); next(new HttpSuccess(202, { taskId })); diff --git a/src/updater.js b/src/updater.js index 5d493940b..230fa2351 100644 --- a/src/updater.js +++ b/src/updater.js @@ -2,14 +2,13 @@ exports = module.exports = { updateToLatest: updateToLatest, - update: update, - - UpdaterError: UpdaterError + update: update }; var apps = require('./apps.js'), assert = require('assert'), async = require('async'), + BoxError = require('./boxerror.js'), child_process = require('child_process'), backups = require('./backups.js'), constants = require('./constants.js'), @@ -26,44 +25,17 @@ var apps = require('./apps.js'), semver = require('semver'), shell = require('./shell.js'), tasks = require('./tasks.js'), - updateChecker = require('./updatechecker.js'), - util = require('util'); + updateChecker = require('./updatechecker.js'); const RELEASES_PUBLIC_KEY = path.join(__dirname, 'releases.gpg'); const UPDATE_CMD = path.join(__dirname, 'scripts/update.sh'); -function UpdaterError(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(UpdaterError, Error); -UpdaterError.INTERNAL_ERROR = 'Internal Error'; -UpdaterError.EXTERNAL_ERROR = 'External Error'; -UpdaterError.BAD_STATE = 'Bad state'; -UpdaterError.ALREADY_UPTODATE = 'No Update Available'; -UpdaterError.NOT_FOUND = 'Not found'; -UpdaterError.NOT_SIGNED = 'Not signed'; - function downloadUrl(url, file, callback) { assert.strictEqual(typeof file, 'string'); assert.strictEqual(typeof callback, 'function'); // do not assert since it comes from the appstore - if (typeof url !== 'string') return callback(new UpdaterError(UpdaterError.EXTERNAL_ERROR, `url cannot be download to ${file} as it is not a string`)); + if (typeof url !== 'string') return callback(new BoxError(BoxError.EXTERNAL_ERROR, `url cannot be download to ${file} as it is not a string`)); let retryCount = 0; @@ -77,7 +49,7 @@ function downloadUrl(url, file, callback) { debug(`downloadUrl: curl ${args}`); shell.spawn('downloadUrl', '/usr/bin/curl', args.split(' '), {}, function (error) { - if (error) return retryCallback(new UpdaterError(UpdaterError.EXTERNAL_ERROR, `Failed to download ${url}: ${error.message}`)); + if (error) return retryCallback(new BoxError(BoxError.NETWORK_ERROR, `Failed to download ${url}: ${error.message}`)); debug(`downloadUrl: downloadUrl ${url} to ${file}`); @@ -92,13 +64,13 @@ function gpgVerify(file, sig, callback) { debug(`gpgVerify: ${cmd}`); child_process.exec(cmd, { encoding: 'utf8' }, function (error, stdout, stderr) { - if (error) return callback(new UpdaterError(UpdaterError.NOT_SIGNED, `The signature in ${path.basename(sig)} could not verified`)); + if (error) return callback(new BoxError(BoxError.NOT_SIGNED, `The signature in ${path.basename(sig)} could not verified`)); if (stdout.indexOf('[GNUPG:] VALIDSIG 0EADB19CDDA23CD0FE71E3470A372F8703C493CC')) return callback(); debug(`gpgVerify: verification of ${sig} failed: ${stdout}\n${stderr}`); - return callback(new UpdaterError(UpdaterError.NOT_SIGNED, `The signature in ${path.basename(sig)} could not verified`)); + return callback(new BoxError(BoxError.NOT_SIGNED, `The signature in ${path.basename(sig)} could not verified`)); }); } @@ -108,7 +80,7 @@ function extractTarball(tarball, dir, callback) { debug(`extractTarball: tar ${args}`); shell.spawn('extractTarball', '/bin/tar', args.split(' '), {}, function (error) { - if (error) return callback(new UpdaterError(UpdaterError.EXTERNAL_ERROR, `Failed to extract release package: ${error.message}`)); + if (error) return callback(new BoxError(BoxError.FS_ERROR, `Failed to extract release package: ${error.message}`)); safe.fs.unlinkSync(tarball); @@ -124,10 +96,10 @@ function verifyUpdateInfo(versionsFile, updateInfo, callback) { assert.strictEqual(typeof callback, 'function'); var releases = safe.JSON.parse(safe.fs.readFileSync(versionsFile, 'utf8')) || { }; - if (!releases[constants.VERSION] || !releases[constants.VERSION].next) return callback(new UpdaterError(UpdaterError.EXTERNAL_ERROR, 'No version info')); + if (!releases[constants.VERSION] || !releases[constants.VERSION].next) return callback(new BoxError(BoxError.EXTERNAL_ERROR, 'No version info')); var nextVersion = releases[constants.VERSION].next; - if (typeof releases[nextVersion] !== 'object' || !releases[nextVersion]) return callback(new UpdaterError(UpdaterError.EXTERNAL_ERROR, 'No next version info')); - if (releases[nextVersion].sourceTarballUrl !== updateInfo.sourceTarballUrl) return callback(new UpdaterError(UpdaterError.EXTERNAL_ERROR, 'Version info mismatch')); + if (typeof releases[nextVersion] !== 'object' || !releases[nextVersion]) return callback(new BoxError(BoxError.EXTERNAL_ERROR, 'No next version info')); + if (releases[nextVersion].sourceTarballUrl !== updateInfo.sourceTarballUrl) return callback(new BoxError(BoxError.EXTERNAL_ERROR, 'Version info mismatch')); callback(); } @@ -161,11 +133,11 @@ function checkFreeDiskSpace(neededSpace, callback) { // can probably be a bit more aggressive here since a new update can bring in new docker images df.file('/').then(function (diskUsage) { - if (diskUsage.available < neededSpace) return callback(new UpdaterError(UpdaterError.NO_SPACE, 'Not enough disk space')); + if (diskUsage.available < neededSpace) return callback(new BoxError(BoxError.FS_ERROR, 'Not enough disk space')); callback(null); }).catch(function (error) { - callback(new UpdaterError(UpdaterError.INTERNAL_ERROR, error)); + callback(new BoxError(BoxError.FS_ERROR, error)); }); } @@ -216,12 +188,12 @@ function canUpdate(boxUpdateInfo, callback) { assert.strictEqual(typeof callback, 'function'); apps.getAll(function (error, result) { - if (error) return callback(new UpdaterError(UpdaterError.INTERNAL_ERROR, error)); + if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error)); for (let app of result) { const maxBoxVersion = app.manifest.maxBoxVersion; if (semver.valid(maxBoxVersion) && semver.gt(boxUpdateInfo.version, maxBoxVersion)) { - return callback(new UpdaterError(UpdaterError.BAD_STATE, `Cannot update to v${boxUpdateInfo.version} because ${app.fqdn} has a maxBoxVersion of ${maxBoxVersion}`)); + return callback(new BoxError(BoxError.BAD_STATE, `Cannot update to v${boxUpdateInfo.version} because ${app.fqdn} has a maxBoxVersion of ${maxBoxVersion}`)); } } @@ -235,17 +207,17 @@ function updateToLatest(options, auditSource, callback) { assert.strictEqual(typeof callback, 'function'); var boxUpdateInfo = updateChecker.getUpdateInfo().box; - if (!boxUpdateInfo) return callback(new UpdaterError(UpdaterError.ALREADY_UPTODATE, 'No update available')); - if (!boxUpdateInfo.sourceTarballUrl) return callback(new UpdaterError(UpdaterError.BAD_STATE, 'No automatic update available')); + if (!boxUpdateInfo) return callback(new BoxError(BoxError.NOT_FOUND, 'No update available')); + if (!boxUpdateInfo.sourceTarballUrl) return callback(new BoxError(BoxError.BAD_STATE, 'No automatic update available')); canUpdate(boxUpdateInfo, function (error) { if (error) return callback(error); error = locker.lock(locker.OP_BOX_UPDATE); - if (error) return callback(new UpdaterError(UpdaterError.BAD_STATE, `Cannot update now: ${error.message}`)); + if (error) return callback(new BoxError(BoxError.BAD_STATE, `Cannot update now: ${error.message}`)); tasks.add(tasks.TASK_UPDATE, [ boxUpdateInfo, options ], function (error, taskId) { - if (error) return callback(new UpdaterError(UpdaterError.INTERNAL_ERROR, error)); + if (error) return callback(error); eventlog.add(eventlog.ACTION_UPDATE, auditSource, { taskId, boxUpdateInfo });