diff --git a/src/node/handler/PadMessageHandler.js b/src/node/handler/PadMessageHandler.js index 9a1885b73..6c4708f08 100644 --- a/src/node/handler/PadMessageHandler.js +++ b/src/node/handler/PadMessageHandler.js @@ -39,6 +39,7 @@ const stats = require('../stats'); const assert = require('assert').strict; const {RateLimiterMemory} = require('rate-limiter-flexible'); const webaccess = require('../hooks/express/webaccess'); +const { checkValidRev } = require('../utils/checkValidRev'); let rateLimiter; let socketio = null; @@ -1076,6 +1077,7 @@ const handleChangesetRequest = async (socket, {data: {granularity, start, reques if (granularity == null) throw new Error('missing granularity'); if (!Number.isInteger(granularity)) throw new Error('granularity is not an integer'); if (start == null) throw new Error('missing start'); + start = checkValidRev(start); if (requestID == null) throw new Error('mising requestID'); const end = start + (100 * granularity); const {padId, author: authorId} = sessioninfos[socket.id]; diff --git a/src/tests/backend/specs/messages.js b/src/tests/backend/specs/messages.js index bccb2584d..f362d58b0 100644 --- a/src/tests/backend/specs/messages.js +++ b/src/tests/backend/specs/messages.js @@ -77,6 +77,62 @@ describe(__filename, function () { await otherPad.remove(); } }); + + it('CHANGESET_REQ: verify revNum is a number (regression)', async function () { + const otherPadId = `${padId}other`; + assert(!await padManager.doesPadExist(otherPadId)); + const otherPad = await padManager.getPad(otherPadId, 'other text\n'); + let errorCatched = 0; + try { + await otherPad.setText('other text\n'); + await common.sendMessage(roSocket, { + component: 'pad', + padId: otherPadId, // The server should ignore this. + type: 'CHANGESET_REQ', + data: { + granularity: 1, + start: 'test123', + requestID: 'requestId', + }, + }); + assert.equal('This code should never run', 1); + } + catch(e) { + assert.match(e.message, /rev is not a number/); + errorCatched = 1; + } + finally { + await otherPad.remove(); + assert.equal(errorCatched, 1); + } + }); + + it('CHANGESET_REQ: revNum is converted to number if possible (regression)', async function () { + const otherPadId = `${padId}other`; + assert(!await padManager.doesPadExist(otherPadId)); + const otherPad = await padManager.getPad(otherPadId, 'other text\n'); + try { + await otherPad.setText('other text\n'); + const resP = common.waitForSocketEvent(roSocket, 'message'); + await common.sendMessage(roSocket, { + component: 'pad', + padId: otherPadId, // The server should ignore this. + type: 'CHANGESET_REQ', + data: { + granularity: 1, + start: '1test123', + requestID: 'requestId', + }, + }); + const res = await resP; + assert.equal(res.type, 'CHANGESET_REQ'); + assert.equal(res.data.requestID, 'requestId'); + assert.equal(res.data.start, 1); + } + finally { + await otherPad.remove(); + } + }); }); describe('USER_CHANGES', function () {