diff --git a/CHANGES b/CHANGES index f844d11a9..1e664415e 100644 --- a/CHANGES +++ b/CHANGES @@ -1927,4 +1927,5 @@ * Add per-app redis status and configuration to Services * spam: large emails were not scanned * mail relay: fix delivery event log +* manual update check always gets the latest updates diff --git a/src/appstore.js b/src/appstore.js index 04e186f43..fa2cef44c 100644 --- a/src/appstore.js +++ b/src/appstore.js @@ -340,7 +340,8 @@ function sendAliveStatus(callback) { }); } -function getBoxUpdate(callback) { +function getBoxUpdate(options, callback) { + assert.strictEqual(typeof options, 'object'); assert.strictEqual(typeof callback, 'function'); getCloudronToken(function (error, token) { @@ -348,7 +349,13 @@ function getBoxUpdate(callback) { const url = `${settings.apiServerOrigin()}/api/v1/boxupdate`; - superagent.get(url).query({ accessToken: token, boxVersion: constants.VERSION }).timeout(10 * 1000).end(function (error, result) { + const query = { + accessToken: token, + boxVersion: constants.VERSION, + automatic: options.automatic + }; + + superagent.get(url).query(query).timeout(10 * 1000).end(function (error, result) { if (error && !error.response) return callback(new BoxError(BoxError.NETWORK_ERROR, error.message)); if (result.statusCode === 401) return callback(new BoxError(BoxError.INVALID_CREDENTIALS)); if (result.statusCode === 422) return callback(new BoxError(BoxError.LICENSE_ERROR, result.body.message)); @@ -374,16 +381,24 @@ function getBoxUpdate(callback) { }); } -function getAppUpdate(app, callback) { +function getAppUpdate(app, options, callback) { assert.strictEqual(typeof app, 'object'); + assert.strictEqual(typeof options, 'object'); assert.strictEqual(typeof callback, 'function'); getCloudronToken(function (error, token) { if (error) return callback(error); const url = `${settings.apiServerOrigin()}/api/v1/appupdate`; + const query = { + accessToken: token, + boxVersion: constants.VERSION, + appId: app.appStoreId, + appVersion: app.manifest.version, + automatic: options.automatic + }; - superagent.get(url).query({ accessToken: token, boxVersion: constants.VERSION, appId: app.appStoreId, appVersion: app.manifest.version }).timeout(10 * 1000).end(function (error, result) { + superagent.get(url).query(query).timeout(10 * 1000).end(function (error, result) { if (error && !error.response) return callback(new BoxError(BoxError.NETWORK_ERROR, error)); if (result.statusCode === 401) return callback(new BoxError(BoxError.INVALID_CREDENTIALS)); if (result.statusCode === 422) return callback(new BoxError(BoxError.LICENSE_ERROR, result.body.message)); diff --git a/src/cron.js b/src/cron.js index 24290258f..3e2a0c1a8 100644 --- a/src/cron.js +++ b/src/cron.js @@ -81,13 +81,13 @@ function startJobs(callback) { gJobs.boxUpdateCheckerJob = new CronJob({ cronTime: '00 ' + randomMinute + ' * * * *', // once an hour - onTick: () => updateChecker.checkBoxUpdates(NOOP_CALLBACK), + onTick: () => updateChecker.checkBoxUpdates({ automatic: true }, NOOP_CALLBACK), start: true }); gJobs.appUpdateChecker = new CronJob({ cronTime: '00 ' + randomMinute + ' * * * *', // once an hour - onTick: () => updateChecker.checkAppUpdates(NOOP_CALLBACK), + onTick: () => updateChecker.checkAppUpdates({ automatic: true }, NOOP_CALLBACK), start: true }); diff --git a/src/routes/cloudron.js b/src/routes/cloudron.js index 4b71ce214..0c9a4ab65 100644 --- a/src/routes/cloudron.js +++ b/src/routes/cloudron.js @@ -218,8 +218,8 @@ function checkForUpdates(req, res, next) { req.clearTimeout(); async.series([ - updateChecker.checkAppUpdates, - updateChecker.checkBoxUpdates + (done) => updateChecker.checkAppUpdates({ automatic: false }, done), + (done) => updateChecker.checkBoxUpdates({ automatic: false }, done), ], function () { next(new HttpSuccess(200, { update: updateChecker.getUpdateInfo() })); }); diff --git a/src/test/updatechecker-test.js b/src/test/updatechecker-test.js index a18f60d66..481a59eac 100644 --- a/src/test/updatechecker-test.js +++ b/src/test/updatechecker-test.js @@ -13,7 +13,6 @@ var appdb = require('../appdb.js'), database = require('../database.js'), domains = require('../domains.js'), expect = require('expect.js'), - mail = require('../mail.js'), mailer = require('../mailer.js'), nock = require('nock'), paths = require('../paths.js'), @@ -95,10 +94,10 @@ describe('updatechecker - box - manual (email)', function () { var scope = nock('http://localhost:4444') .get('/api/v1/boxupdate') - .query({ boxVersion: constants.VERSION, accessToken: 'atoken' }) + .query({ boxVersion: constants.VERSION, accessToken: 'atoken', automatic: false }) .reply(204, { } ); - updatechecker.checkBoxUpdates(function (error) { + updatechecker.checkBoxUpdates({ automatic: false }, function (error) { expect(!error).to.be.ok(); expect(updatechecker.getUpdateInfo().box).to.be(null); expect(scope.isDone()).to.be.ok(); @@ -112,10 +111,10 @@ describe('updatechecker - box - manual (email)', function () { var scope = nock('http://localhost:4444') .get('/api/v1/boxupdate') - .query({ boxVersion: constants.VERSION, accessToken: 'atoken' }) + .query({ boxVersion: constants.VERSION, accessToken: 'atoken', automatic: false }) .reply(200, { version: UPDATE_VERSION, changelog: [''], sourceTarballUrl: 'box.tar.gz', sourceTarballSigUrl: 'box.tar.gz.sig', boxVersionsUrl: 'box.versions', boxVersionsSigUrl: 'box.versions.sig' } ); - updatechecker.checkBoxUpdates(function (error) { + updatechecker.checkBoxUpdates({ automatic: false }, function (error) { expect(!error).to.be.ok(); expect(updatechecker.getUpdateInfo().box.version).to.be(UPDATE_VERSION); expect(updatechecker.getUpdateInfo().box.sourceTarballUrl).to.be('box.tar.gz'); @@ -130,10 +129,10 @@ describe('updatechecker - box - manual (email)', function () { var scope = nock('http://localhost:4444') .get('/api/v1/boxupdate') - .query({ boxVersion: constants.VERSION, accessToken: 'atoken' }) + .query({ boxVersion: constants.VERSION, accessToken: 'atoken', automatic: false }) .reply(404, { version: '2.0.0-pre.0', changelog: [''], sourceTarballUrl: 'box-pre.tar.gz' } ); - updatechecker.checkBoxUpdates(function (error) { + updatechecker.checkBoxUpdates({ automatic: false }, function (error) { expect(error).to.be.ok(); expect(updatechecker.getUpdateInfo().box).to.be(null); expect(scope.isDone()).to.be.ok(); @@ -165,10 +164,10 @@ describe('updatechecker - box - automatic (no email)', function () { var scope = nock('http://localhost:4444') .get('/api/v1/boxupdate') - .query({ boxVersion: constants.VERSION, accessToken: 'atoken' }) + .query({ boxVersion: constants.VERSION, accessToken: 'atoken', automatic: false }) .reply(200, { version: UPDATE_VERSION, changelog: [''], sourceTarballUrl: 'box.tar.gz', sourceTarballSigUrl: 'box.tar.gz.sig', boxVersionsUrl: 'box.versions', boxVersionsSigUrl: 'box.versions.sig' } ); - updatechecker.checkBoxUpdates(function (error) { + updatechecker.checkBoxUpdates({ automatic: false }, function (error) { expect(!error).to.be.ok(); expect(updatechecker.getUpdateInfo().box.version).to.be(UPDATE_VERSION); expect(scope.isDone()).to.be.ok(); @@ -200,10 +199,10 @@ describe('updatechecker - box - automatic free (email)', function () { var scope = nock('http://localhost:4444') .get('/api/v1/boxupdate') - .query({ boxVersion: constants.VERSION, accessToken: 'atoken' }) + .query({ boxVersion: constants.VERSION, accessToken: 'atoken', automatic: false }) .reply(200, { version: UPDATE_VERSION, changelog: [''], sourceTarballUrl: 'box.tar.gz', sourceTarballSigUrl: 'box.tar.gz.sig', boxVersionsUrl: 'box.versions', boxVersionsSigUrl: 'box.versions.sig' } ); - updatechecker.checkBoxUpdates(function (error) { + updatechecker.checkBoxUpdates({ automatic: false }, function (error) { expect(!error).to.be.ok(); expect(updatechecker.getUpdateInfo().box.version).to.be(UPDATE_VERSION); expect(scope.isDone()).to.be.ok(); @@ -265,10 +264,10 @@ describe('updatechecker - app - manual (email)', function () { var scope = nock('http://localhost:4444') .get('/api/v1/appupdate') - .query({ boxVersion: constants.VERSION, accessToken: 'atoken', appId: APP_0.appStoreId, appVersion: APP_0.manifest.version }) + .query({ boxVersion: constants.VERSION, accessToken: 'atoken', appId: APP_0.appStoreId, appVersion: APP_0.manifest.version, automatic: false }) .reply(204, { } ); - updatechecker.checkAppUpdates(function (error) { + updatechecker.checkAppUpdates({ automatic: false }, function (error) { expect(!error).to.be.ok(); expect(updatechecker.getUpdateInfo().apps).to.eql({}); expect(scope.isDone()).to.be.ok(); @@ -282,10 +281,10 @@ describe('updatechecker - app - manual (email)', function () { var scope = nock('http://localhost:4444') .get('/api/v1/appupdate') - .query({ boxVersion: constants.VERSION, accessToken: 'atoken', appId: APP_0.appStoreId, appVersion: APP_0.manifest.version }) + .query({ boxVersion: constants.VERSION, accessToken: 'atoken', appId: APP_0.appStoreId, appVersion: APP_0.manifest.version, automatic: false }) .reply(500, { update: { manifest: { version: '1.0.0', changelog: '* some changes' } } } ); - updatechecker.checkAppUpdates(function (error) { + updatechecker.checkAppUpdates({ automatic: false }, function (error) { expect(!error).to.be.ok(); expect(updatechecker.getUpdateInfo().apps).to.eql({}); expect(scope.isDone()).to.be.ok(); @@ -299,10 +298,10 @@ describe('updatechecker - app - manual (email)', function () { var scope = nock('http://localhost:4444') .get('/api/v1/appupdate') - .query({ boxVersion: constants.VERSION, accessToken: 'atoken', appId: APP_0.appStoreId, appVersion: APP_0.manifest.version }) + .query({ boxVersion: constants.VERSION, accessToken: 'atoken', appId: APP_0.appStoreId, appVersion: APP_0.manifest.version, automatic: false }) .reply(200, { manifest: { version: '2.0.0', changelog: '* some changes' } } ); - updatechecker.checkAppUpdates(function (error) { + updatechecker.checkAppUpdates({ automatic: false }, function (error) { expect(!error).to.be.ok(); expect(updatechecker.getUpdateInfo().apps).to.eql({ 'appid-0': { manifest: { version: '2.0.0', changelog: '* some changes' } } }); expect(scope.isDone()).to.be.ok(); @@ -314,7 +313,7 @@ describe('updatechecker - app - manual (email)', function () { it('does not offer old version', function (done) { nock.cleanAll(); - updatechecker.checkAppUpdates(function (error) { + updatechecker.checkAppUpdates({ automatic: false }, function (error) { expect(!error).to.be.ok(); expect(updatechecker.getUpdateInfo().apps).to.eql({ }); checkMails(0, done); @@ -374,10 +373,10 @@ describe('updatechecker - app - automatic (no email)', function () { var scope = nock('http://localhost:4444') .get('/api/v1/appupdate') - .query({ boxVersion: constants.VERSION, accessToken: 'atoken', appId: APP_0.appStoreId, appVersion: APP_0.manifest.version }) + .query({ boxVersion: constants.VERSION, accessToken: 'atoken', appId: APP_0.appStoreId, appVersion: APP_0.manifest.version, automatic: false }) .reply(200, { manifest: { version: '2.0.0', changelog: 'c' } } ); - updatechecker.checkAppUpdates(function (error) { + updatechecker.checkAppUpdates({ automatic: false }, function (error) { expect(!error).to.be.ok(); expect(updatechecker.getUpdateInfo().apps).to.eql({ 'appid-0': { manifest: { version: '2.0.0', changelog: 'c' } } }); expect(scope.isDone()).to.be.ok(); @@ -439,10 +438,10 @@ describe('updatechecker - app - automatic free (email)', function () { var scope = nock('http://localhost:4444') .get('/api/v1/appupdate') - .query({ boxVersion: constants.VERSION, accessToken: 'atoken', appId: APP_0.appStoreId, appVersion: APP_0.manifest.version }) + .query({ boxVersion: constants.VERSION, accessToken: 'atoken', appId: APP_0.appStoreId, appVersion: APP_0.manifest.version, automatic: false }) .reply(200, { manifest: { version: '2.0.0', changelog: 'c' } } ); - updatechecker.checkAppUpdates(function (error) { + updatechecker.checkAppUpdates({ automatic: false }, function (error) { expect(!error).to.be.ok(); expect(updatechecker.getUpdateInfo().apps).to.eql({ 'appid-0': { manifest: { version: '2.0.0', changelog: 'c' } } }); expect(scope.isDone()).to.be.ok(); diff --git a/src/updatechecker.js b/src/updatechecker.js index 6f49a137f..3c1461475 100644 --- a/src/updatechecker.js +++ b/src/updatechecker.js @@ -62,7 +62,8 @@ function resetAppUpdateInfo(appId) { } } -function checkAppUpdates(callback) { +function checkAppUpdates(options, callback) { + assert.strictEqual(typeof options, 'object'); assert.strictEqual(typeof callback, 'function'); debug('Checking App Updates'); @@ -84,7 +85,7 @@ function checkAppUpdates(callback) { if (app.appStoreId === '') return iteratorDone(); // appStoreId can be '' for dev apps if (app.runState === apps.RSTATE_STOPPED) return iteratorDone(); // stopped apps won't run migration scripts and shouldn't be updated - appstore.getAppUpdate(app, function (error, updateInfo) { + appstore.getAppUpdate(app, options, function (error, updateInfo) { if (error) { debug('Error getting app update info for %s', app.id, error); return iteratorDone(); // continue to next @@ -136,14 +137,15 @@ function checkAppUpdates(callback) { }); } -function checkBoxUpdates(callback) { +function checkBoxUpdates(options, callback) { + assert.strictEqual(typeof options, 'object'); assert.strictEqual(typeof callback, 'function'); debug('Checking Box Updates'); gBoxUpdateInfo = null; - appstore.getBoxUpdate(function (error, updateInfo) { + appstore.getBoxUpdate(options, function (error, updateInfo) { if (error || !updateInfo) return callback(error); gBoxUpdateInfo = updateInfo;