mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-01-20 22:42:53 -05:00
🐛 Fixed triggering wrong error for invalid client versions
fix https://linear.app/ghost/issue/ENG-1502/handle-malformed-client-versions-to-avoid-versionmismatcherror - in the event we pass a client version that is invalid (ie, anything that doesn't resemble semver version), we currently throw a VersionMismatchError - this is slightly misleading because although it is a version mismatch, it moreso that it's an invalid string to pass in this header - to fix that, we can just use `validRange` from `semver` to detect this, and throw a BadRequestError with a meaningful error message - this helps us detect whether the header is actually a version mismatch, or an invalid input
This commit is contained in:
parent
52d15cf955
commit
4b51942403
2 changed files with 35 additions and 11 deletions
|
@ -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();
|
||||
|
|
|
@ -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';
|
||||
|
|
Loading…
Add table
Reference in a new issue