diff --git a/ghost/mw-version-match/lib/mw-version-match.js b/ghost/mw-version-match/lib/mw-version-match.js index a13c97df3d..ee6c2c149b 100644 --- a/ghost/mw-version-match/lib/mw-version-match.js +++ b/ghost/mw-version-match/lib/mw-version-match.js @@ -3,6 +3,7 @@ const errors = require('@tryghost/errors'); const tpl = require('@tryghost/tpl'); const messages = { + invalidClientVersionRange: 'Client request for {clientVersion} is invalid.', versionMismatch: 'Client request for {clientVersion} does not match server version {serverVersion}.' }; @@ -10,19 +11,30 @@ function checkVersionMatch(req, res, next) { const clientVersion = req.get('X-Ghost-Version'); // can contain pre-release suffix, you should be able to use e.g. 1.19.0-pre [server] with 1.18.0 [client] const serverVersion = res.locals.version.match(/^(\d+\.)?(\d+\.)?(\d+)/)[0]; - const constraint = '^' + clientVersion + '.0'; - // no error when client is on an earlier minor version than server - // error when client is on a later minor version than server - // always error when the major version is different + if (clientVersion) { + const constraint = '^' + clientVersion + '.0'; - if (clientVersion && !semver.satisfies(serverVersion, constraint)) { - return next(new errors.VersionMismatchError({ - message: tpl(messages.versionMismatch, { - clientVersion: clientVersion, - serverVersion: serverVersion - }) - })); + // Protect against invalid client ranges + if (!semver.validRange(constraint)) { + return next(new errors.BadRequestError({ + message: tpl(messages.invalidClientVersionRange, { + clientVersion + }) + })); + } + + // no error when client is on an earlier minor version than server + // error when client is on a later minor version than server + // always error when the major version is different + if (!semver.satisfies(serverVersion, constraint)) { + return next(new errors.VersionMismatchError({ + message: tpl(messages.versionMismatch, { + clientVersion, + serverVersion + }) + })); + } } next(); diff --git a/ghost/mw-version-match/test/version-match.test.js b/ghost/mw-version-match/test/version-match.test.js index fd76e00145..e065fe4db7 100644 --- a/ghost/mw-version-match/test/version-match.test.js +++ b/ghost/mw-version-match/test/version-match.test.js @@ -66,6 +66,18 @@ describe('Version Mismatch', function () { nextStub.firstCall.args.should.be.empty(); }); + it('should throw BadRequestError if client version is invalid', function () { + const server = '1.5.0'; + const client = 'bananarama'; + + testVersionMatch(server, client); + + nextStub.calledOnce.should.be.true(); + nextStub.firstCall.args.should.have.lengthOf(1); + nextStub.firstCall.args[0].should.have.property('errorType', 'BadRequestError'); + nextStub.firstCall.args[0].should.have.property('statusCode', 400); + }); + it('should throw VersionMismatchError if client version is earlier by a major version', function () { const server = '2.5.0'; const client = '1.3';