Merge branch 'develop' of github.com:ether/etherpad-lite into f3

This commit is contained in:
John McLear 2023-06-26 19:32:52 +01:00
commit 02fe05bde2
20 changed files with 463 additions and 322 deletions

View file

@ -18,7 +18,7 @@ jobs:
strategy:
fail-fast: false
matrix:
node: [14, 16, 18]
node: [16, 18, 20]
steps:
-
name: Checkout repository
@ -55,7 +55,7 @@ jobs:
strategy:
fail-fast: false
matrix:
node: [14, 16, 18]
node: [16, 18, 20]
steps:
-
name: Checkout repository
@ -124,7 +124,7 @@ jobs:
-
uses: actions/setup-node@v3
with:
node-version: 14
node-version: 20
cache: 'npm'
cache-dependency-path: |
src/package-lock.json
@ -157,7 +157,7 @@ jobs:
-
uses: actions/setup-node@v3
with:
node-version: 14
node-version: 20
cache: 'npm'
cache-dependency-path: |
src/package-lock.json

View file

@ -14,7 +14,7 @@ jobs:
strategy:
fail-fast: false
matrix:
node: [14, 16, 18]
node: [16, 18, 20]
steps:
-

View file

@ -34,7 +34,7 @@ jobs:
-
uses: actions/setup-node@v3
with:
node-version: 14
node-version: 20
cache: 'npm'
cache-dependency-path: |
src/package-lock.json
@ -98,7 +98,7 @@ jobs:
-
uses: actions/setup-node@v3
with:
node-version: 14
node-version: 20
cache: 'npm'
cache-dependency-path: |
src/package-lock.json
@ -126,7 +126,7 @@ jobs:
# Etherpad core dependencies must be installed after installing the
# plugin's dependencies, otherwise npm will try to hoist common
# dependencies by removing them from src/node_modules and installing them
# in the top-level node_modules. As of v6.14.10, npm's hoist logic appears
# in the top-level node_modules. As of v6.20.10, npm's hoist logic appears
# to be buggy, because it sometimes removes dependencies from
# src/node_modules but fails to add them to the top-level node_modules.
# Even if npm correctly hoists the dependencies, the hoisting seems to

View file

@ -22,7 +22,7 @@ jobs:
-
uses: actions/setup-node@v3
with:
node-version: 14
node-version: 20
cache: 'npm'
cache-dependency-path: |
src/package-lock.json

View file

@ -22,7 +22,7 @@ jobs:
-
uses: actions/setup-node@v3
with:
node-version: 14
node-version: 20
cache: 'npm'
cache-dependency-path: |
src/package-lock.json
@ -52,7 +52,7 @@ jobs:
-
uses: actions/setup-node@v3
with:
node-version: 14
node-version: 20
cache: 'npm'
cache-dependency-path: |
src/package-lock.json
@ -109,7 +109,7 @@ jobs:
-
uses: actions/setup-node@v3
with:
node-version: 14
node-version: 20
cache: 'npm'
cache-dependency-path: |
src/package-lock.json

View file

@ -22,7 +22,7 @@ jobs:
-
uses: actions/setup-node@v3
with:
node-version: 14
node-version: 20
cache: 'npm'
cache-dependency-path: |
src/package-lock.json

View file

@ -18,7 +18,7 @@ jobs:
strategy:
fail-fast: false
matrix:
node: [14, 16, 18]
node: [16, 18, 20]
steps:
-
name: Check out latest release

View file

@ -28,7 +28,7 @@ jobs:
-
uses: actions/setup-node@v3
with:
node-version: 14
node-version: 20
cache: 'npm'
cache-dependency-path: |
src/package-lock.json
@ -108,7 +108,7 @@ jobs:
-
uses: actions/setup-node@v3
with:
node-version: 14
node-version: 20
cache: 'npm'
cache-dependency-path: |
etherpad/src/package-lock.json

View file

@ -1,3 +1,14 @@
# Next release
### Notable enhancements and fixes
* Security
* Limit requested revisions in timeslider and export to head revision. (affects v1.9.0)
* Bugfixes
* revisions in `CHANGESET_REQ` (timeslider) and export (txt, html, custom)
are now checked to be numbers.
# 1.9.0
### Notable enhancements and fixes

View file

@ -46,7 +46,7 @@ We're looking for maintainers and have some funding available. Please contact J
### Requirements
[Node.js](https://nodejs.org/) >= **14.0.0**.
[Node.js](https://nodejs.org/) >= **16.20.1**.
### GNU/Linux and other UNIX-like systems

View file

@ -33,6 +33,7 @@ const exportTxt = require('../utils/ExportTxt');
const importHtml = require('../utils/ImportHtml');
const cleanText = require('./Pad').cleanText;
const PadDiff = require('../utils/padDiff');
const { checkValidRev, isInt } = require('../utils/checkValidRev');
/* ********************
* GROUP FUNCTIONS ****
@ -777,6 +778,13 @@ exports.createDiffHTML = async (padID, startRev, endRev) => {
// get the pad
const pad = await getPadSafe(padID, true);
const headRev = pad.getHeadRevisionNumber();
if (startRev > headRev)
startRev = headRev;
if (endRev > headRev)
endRev = headRev;
let padDiff;
try {
padDiff = new PadDiff(pad, startRev, endRev);
@ -822,9 +830,6 @@ exports.getStats = async () => {
** INTERNAL HELPER FUNCTIONS *
**************************** */
// checks if a number is an int
const isInt = (value) => (parseFloat(value) === parseInt(value, 10)) && !isNaN(value);
// gets a pad safe
const getPadSafe = async (padID, shouldExist, text, authorId = '') => {
// check if padID is a string
@ -854,31 +859,6 @@ const getPadSafe = async (padID, shouldExist, text, authorId = '') => {
return padManager.getPad(padID, text, authorId);
};
// checks if a rev is a legal number
// pre-condition is that `rev` is not undefined
const checkValidRev = (rev) => {
if (typeof rev !== 'number') {
rev = parseInt(rev, 10);
}
// check if rev is a number
if (isNaN(rev)) {
throw new CustomError('rev is not a number', 'apierror');
}
// ensure this is not a negative number
if (rev < 0) {
throw new CustomError('rev is not a negative number', 'apierror');
}
// ensure this is not a float value
if (!isInt(rev)) {
throw new CustomError('rev is a float value', 'apierror');
}
return rev;
};
// checks if a padID is part of a group
const checkGroupPad = (padID, field) => {
// ensure this is a group pad

View file

@ -172,6 +172,9 @@ class Pad {
async getInternalRevisionAText(targetRev) {
const keyRev = this.getKeyRevisionNumber(targetRev);
const headRev = this.getHeadRevisionNumber();
if (targetRev > headRev)
targetRev = headRev;
const [keyAText, changesets] = await Promise.all([
this._getKeyRevisionAText(keyRev),
Promise.all(

View file

@ -29,6 +29,7 @@ const os = require('os');
const hooks = require('../../static/js/pluginfw/hooks');
const TidyHtml = require('../utils/TidyHtml');
const util = require('util');
const { checkValidRev } = require('../utils/checkValidRev');
const fsp_writeFile = util.promisify(fs.writeFile);
const fsp_unlink = util.promisify(fs.unlink);
@ -53,6 +54,12 @@ exports.doExport = async (req, res, padId, readOnlyId, type) => {
// tell the browser that this is a downloadable file
res.attachment(`${fileName}.${type}`);
if (req.params.rev !== undefined) {
// ensure revision is a number
// modify req, as we use it in a later call to exportConvert
req.params.rev = checkValidRev(req.params.rev);
}
// if this is a plain text export, we can do this directly
// We have to over engineer this because tabs are stored as attributes and not plain text
if (type === 'etherpad') {

View file

@ -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,10 +1077,14 @@ 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];
const pad = await padManager.getPad(padId, null, authorId);
const headRev = pad.getHeadRevisionNumber();
if (start > headRev)
start = headRev;
const data = await getChangesetInfo(pad, start, end, granularity);
data.requestID = requestID;
socket.json.send({type: 'CHANGESET_REQ', data});

View file

@ -21,10 +21,14 @@
const AttributeMap = require('../../static/js/AttributeMap');
const Changeset = require('../../static/js/Changeset');
const { checkValidRev } = require('./checkValidRev');
/*
* This method seems unused in core and no plugins depend on it
*/
exports.getPadPlainText = (pad, revNum) => {
const _analyzeLine = exports._analyzeLine;
const atext = ((revNum !== undefined) ? pad.getInternalRevisionAText(revNum) : pad.atext);
const atext = ((revNum !== undefined) ? pad.getInternalRevisionAText(checkValidRev(revNum)) : pad.atext);
const textLines = atext.text.slice(0, -1).split('\n');
const attribLines = Changeset.splitAttributionLines(atext.attribs, atext.text);
const apool = pad.pool;

View file

@ -0,0 +1,34 @@
'use strict';
const CustomError = require('../utils/customError');
// checks if a rev is a legal number
// pre-condition is that `rev` is not undefined
const checkValidRev = (rev) => {
if (typeof rev !== 'number') {
rev = parseInt(rev, 10);
}
// check if rev is a number
if (isNaN(rev)) {
throw new CustomError('rev is not a number', 'apierror');
}
// ensure this is not a negative number
if (rev < 0) {
throw new CustomError('rev is not a negative number', 'apierror');
}
// ensure this is not a float value
if (!isInt(rev)) {
throw new CustomError('rev is a float value', 'apierror');
}
return rev;
};
// checks if a number is an int
const isInt = (value) => (parseFloat(value) === parseInt(value, 10)) && !isNaN(value);
exports.isInt = isInt;
exports.checkValidRev = checkValidRev;

389
src/package-lock.json generated
View file

@ -1008,9 +1008,9 @@
"dev": true
},
"abab": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz",
"integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q=="
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz",
"integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA=="
},
"abbrev": {
"version": "1.1.1",
@ -1028,9 +1028,9 @@
}
},
"acorn": {
"version": "8.7.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz",
"integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ=="
"version": "8.9.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.9.0.tgz",
"integrity": "sha512-jaVNAFBHNLXspO543WnNNPZFRtavh3skAkITqD0/2aeMkKZTN+254PyhwxFYrk3vQ1xfY+2wbesJMs/JC8/PwQ=="
},
"acorn-globals": {
"version": "6.0.0",
@ -1142,9 +1142,9 @@
}
},
"anymatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
"integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
"dev": true,
"requires": {
"normalize-path": "^3.0.0",
@ -1619,40 +1619,6 @@
"string-width": "^4.2.0",
"strip-ansi": "^6.0.0",
"wrap-ansi": "^7.0.0"
},
"dependencies": {
"ansi-regex": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"dev": true
},
"is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"dev": true
},
"string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"dev": true,
"requires": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^6.0.1"
}
},
"strip-ansi": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dev": true,
"requires": {
"ansi-regex": "^5.0.1"
}
}
}
},
"cluster-key-slot": {
@ -1811,13 +1777,13 @@
}
},
"data-urls": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.1.tgz",
"integrity": "sha512-Ds554NeT5Gennfoo9KN50Vh6tpgtvYEwraYjejXnyTpu1C7oXKxdFk75REooENHE8ndTVOJuv+BEs4/J/xcozw==",
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz",
"integrity": "sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==",
"requires": {
"abab": "^2.0.3",
"abab": "^2.0.6",
"whatwg-mimetype": "^3.0.0",
"whatwg-url": "^10.0.0"
"whatwg-url": "^11.0.0"
}
},
"debug": {
@ -1835,9 +1801,9 @@
"dev": true
},
"decimal.js": {
"version": "10.3.1",
"resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz",
"integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ=="
"version": "10.4.3",
"resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz",
"integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA=="
},
"deep-is": {
"version": "0.1.4",
@ -2112,6 +2078,11 @@
"has-binary2": "~1.0.2"
}
},
"entities": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="
},
"env-paths": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
@ -3312,12 +3283,6 @@
"integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
"dev": true
},
"growl": {
"version": "1.10.5",
"resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz",
"integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==",
"dev": true
},
"har-schema": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
@ -3574,9 +3539,9 @@
},
"dependencies": {
"debug": {
"version": "4.3.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
"integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==",
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"requires": {
"ms": "2.1.2"
}
@ -3790,8 +3755,7 @@
"is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"optional": true
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
},
"is-glob": {
"version": "4.0.3",
@ -3964,27 +3928,27 @@
"integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM="
},
"jsdom": {
"version": "19.0.0",
"resolved": "https://registry.npmjs.org/jsdom/-/jsdom-19.0.0.tgz",
"integrity": "sha512-RYAyjCbxy/vri/CfnjUWJQQtZ3LKlLnDqj+9XLNnJPgEGeirZs3hllKR20re8LUZ6o1b1X4Jat+Qd26zmP41+A==",
"version": "20.0.0",
"resolved": "https://registry.npmjs.org/jsdom/-/jsdom-20.0.0.tgz",
"integrity": "sha512-x4a6CKCgx00uCmP+QakBDFXwjAJ69IkkIWHmtmjd3wvXPcdOS44hfX2vqkOQrVrq8l9DhNNADZRXaCEWvgXtVA==",
"requires": {
"abab": "^2.0.5",
"acorn": "^8.5.0",
"abab": "^2.0.6",
"acorn": "^8.7.1",
"acorn-globals": "^6.0.0",
"cssom": "^0.5.0",
"cssstyle": "^2.3.0",
"data-urls": "^3.0.1",
"data-urls": "^3.0.2",
"decimal.js": "^10.3.1",
"domexception": "^4.0.0",
"escodegen": "^2.0.0",
"form-data": "^4.0.0",
"html-encoding-sniffer": "^3.0.0",
"http-proxy-agent": "^5.0.0",
"https-proxy-agent": "^5.0.0",
"https-proxy-agent": "^5.0.1",
"is-potential-custom-element-name": "^1.0.1",
"nwsapi": "^2.2.0",
"parse5": "6.0.1",
"saxes": "^5.0.1",
"parse5": "^7.0.0",
"saxes": "^6.0.0",
"symbol-tree": "^3.2.4",
"tough-cookie": "^4.0.0",
"w3c-hr-time": "^1.0.2",
@ -3992,9 +3956,41 @@
"webidl-conversions": "^7.0.0",
"whatwg-encoding": "^2.0.0",
"whatwg-mimetype": "^3.0.0",
"whatwg-url": "^10.0.0",
"ws": "^8.2.3",
"whatwg-url": "^11.0.0",
"ws": "^8.8.0",
"xml-name-validator": "^4.0.0"
},
"dependencies": {
"debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"requires": {
"ms": "2.1.2"
}
},
"https-proxy-agent": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
"integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
"requires": {
"agent-base": "6",
"debug": "4"
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"parse5": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz",
"integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==",
"requires": {
"entities": "^4.4.0"
}
}
}
},
"json-schema": {
@ -4150,7 +4146,7 @@
"levn": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
"integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
"integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==",
"requires": {
"prelude-ls": "~1.1.2",
"type-check": "~0.3.2"
@ -4204,57 +4200,6 @@
"requires": {
"chalk": "^4.1.0",
"is-unicode-supported": "^0.1.0"
},
"dependencies": {
"ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"requires": {
"color-convert": "^2.0.1"
}
},
"chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"dev": true,
"requires": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
}
},
"color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"requires": {
"color-name": "~1.1.4"
}
},
"color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true
},
"supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
"requires": {
"has-flag": "^4.0.0"
}
}
}
},
"log4js": {
@ -4523,41 +4468,48 @@
"optional": true
},
"mocha": {
"version": "9.2.2",
"resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.2.tgz",
"integrity": "sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g==",
"version": "10.0.0",
"resolved": "https://registry.npmjs.org/mocha/-/mocha-10.0.0.tgz",
"integrity": "sha512-0Wl+elVUD43Y0BqPZBzZt8Tnkw9CMUdNYnUsTfOM1vuhJVZL+kiesFYsqwBkEEuEixaiPe5ZQdqDgX2jddhmoA==",
"dev": true,
"requires": {
"@ungap/promise-all-settled": "1.1.2",
"ansi-colors": "4.1.1",
"browser-stdout": "1.3.1",
"chokidar": "3.5.3",
"debug": "4.3.3",
"debug": "4.3.4",
"diff": "5.0.0",
"escape-string-regexp": "4.0.0",
"find-up": "5.0.0",
"glob": "7.2.0",
"growl": "1.10.5",
"he": "1.2.0",
"js-yaml": "4.1.0",
"log-symbols": "4.1.0",
"minimatch": "4.2.1",
"minimatch": "5.0.1",
"ms": "2.1.3",
"nanoid": "3.3.1",
"nanoid": "3.3.3",
"serialize-javascript": "6.0.0",
"strip-json-comments": "3.1.1",
"supports-color": "8.1.1",
"which": "2.0.2",
"workerpool": "6.2.0",
"workerpool": "6.2.1",
"yargs": "16.2.0",
"yargs-parser": "20.2.4",
"yargs-unparser": "2.0.0"
},
"dependencies": {
"brace-expansion": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"dev": true,
"requires": {
"balanced-match": "^1.0.0"
}
},
"debug": {
"version": "4.3.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
"integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==",
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"dev": true,
"requires": {
"ms": "2.1.2"
@ -4587,12 +4539,6 @@
"path-exists": "^4.0.0"
}
},
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true
},
"locate-path": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
@ -4603,12 +4549,12 @@
}
},
"minimatch": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz",
"integrity": "sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==",
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz",
"integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==",
"dev": true,
"requires": {
"brace-expansion": "^1.1.7"
"brace-expansion": "^2.0.1"
}
},
"ms": {
@ -4641,12 +4587,6 @@
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
"dev": true
},
"strip-json-comments": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
"integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
"dev": true
},
"supports-color": {
"version": "8.1.1",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
@ -4764,9 +4704,9 @@
}
},
"nanoid": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz",
"integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==",
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz",
"integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==",
"dev": true
},
"native-duplexpair": {
@ -7976,9 +7916,9 @@
}
},
"nwsapi": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz",
"integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ=="
"version": "2.2.5",
"resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.5.tgz",
"integrity": "sha512-6xpotnECFy/og7tKSBVmUNft7J3jyXAka4XvG6AUhFWRz+Q/Ljus7znJAA3bxColfQLdS+XsjoodtJfCgeTEFQ=="
},
"oauth-sign": {
"version": "0.9.0",
@ -8332,7 +8272,7 @@
"prelude-ls": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
"integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ="
"integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w=="
},
"process": {
"version": "0.11.10",
@ -8686,9 +8626,9 @@
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
},
"saxes": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz",
"integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==",
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz",
"integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==",
"requires": {
"xmlchars": "^2.2.0"
}
@ -8723,9 +8663,9 @@
}
},
"semver": {
"version": "7.5.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.2.tgz",
"integrity": "sha512-SoftuTROv/cRjCze/scjGyiDtcUyxw1rgYQSZY7XTmtR5hX+dm76iDbTH8TkLPHCQmlbQVSSbNZCPM2hb0knnQ==",
"version": "7.5.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz",
"integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==",
"requires": {
"lru-cache": "^6.0.0"
}
@ -9125,7 +9065,6 @@
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"optional": true,
"requires": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
@ -9135,14 +9074,12 @@
"ansi-regex": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"optional": true
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
},
"strip-ansi": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"optional": true,
"requires": {
"ansi-regex": "^5.0.1"
}
@ -9561,7 +9498,7 @@
"type-check": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
"integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
"integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==",
"requires": {
"prelude-ls": "~1.1.2"
}
@ -9978,9 +9915,9 @@
"integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q=="
},
"whatwg-url": {
"version": "10.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-10.0.0.tgz",
"integrity": "sha512-CLxxCmdUby142H5FZzn4D8ikO1cmypvXVQktsgosNy4a4BHrDHeciBBGZhb0bNoR5/MltoCatso+vFjjGx8t0w==",
"version": "11.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz",
"integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==",
"requires": {
"tr46": "^3.0.0",
"webidl-conversions": "^7.0.0"
@ -10021,9 +9958,9 @@
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ=="
},
"workerpool": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz",
"integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==",
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz",
"integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==",
"dev": true
},
"wrap-ansi": {
@ -10035,64 +9972,6 @@
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
"strip-ansi": "^6.0.0"
},
"dependencies": {
"ansi-regex": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"dev": true
},
"ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"requires": {
"color-convert": "^2.0.1"
}
},
"color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"requires": {
"color-name": "~1.1.4"
}
},
"color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
"is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"dev": true
},
"string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"dev": true,
"requires": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^6.0.1"
}
},
"strip-ansi": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dev": true,
"requires": {
"ansi-regex": "^5.0.1"
}
}
}
},
"wrappy": {
@ -10101,9 +9980,9 @@
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
},
"ws": {
"version": "8.5.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz",
"integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg=="
"version": "8.13.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz",
"integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA=="
},
"wtfnode": {
"version": "0.9.1",
@ -10159,40 +10038,6 @@
"string-width": "^4.2.0",
"y18n": "^5.0.5",
"yargs-parser": "^20.2.2"
},
"dependencies": {
"ansi-regex": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"dev": true
},
"is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"dev": true
},
"string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"dev": true,
"requires": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^6.0.1"
}
},
"strip-ansi": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dev": true,
"requires": {
"ansi-regex": "^5.0.1"
}
}
}
},
"yargs-parser": {

View file

@ -45,7 +45,7 @@
"formidable": "^3.1.3",
"http-errors": "^2.0.0",
"js-cookie": "^3.0.5",
"jsdom": "^19.0.0",
"jsdom": "^20.0.0",
"jsonminify": "0.4.2",
"languages4translatewiki": "0.1.3",
"lodash.clonedeep": "4.5.0",
@ -61,7 +61,7 @@
"request": "2.88.2",
"resolve": "1.22.2",
"security": "1.0.0",
"semver": "^7.5.2",
"semver": "^7.5.3",
"socket.io": "^2.4.1",
"superagent": "^8.0.9",
"terser": "^5.18.1",
@ -81,7 +81,7 @@
"eslint": "^8.43.0",
"eslint-config-etherpad": "^3.0.13",
"etherpad-cli-client": "^2.0.1",
"mocha": "^9.2.2",
"mocha": "^10.0.0",
"mocha-froth": "^0.2.10",
"nodeify": "^1.0.1",
"openapi-schema-validation": "^0.4.2",
@ -93,7 +93,7 @@
"typescript": "^4.9.5"
},
"engines": {
"node": ">=14.15.0",
"node": ">=16.20.1",
"npm": ">=6.14.0"
},
"repository": {

View file

@ -447,6 +447,175 @@ describe(__filename, function () {
});
});
describe('revisions are supported in txt and html export', function () {
const makeGoodExport = () => ({
'pad:testing': {
atext: {
text: 'oofoo\n',
attribs: '|1+6',
},
pool: {
numToAttrib: {
0: ['author', 'a.foo'],
},
nextNum: 1,
},
head: 2,
savedRevisions: [],
},
'globalAuthor:a.foo': {
colorId: '#000000',
name: 'author foo',
timestamp: 1598747784631,
padIDs: 'testing',
},
'pad:testing:revs:0': {
changeset: 'Z:1>3+3$foo',
meta: {
author: 'a.foo',
timestamp: 1597632398288,
pool: {
nextNum: 1,
numToAttrib: {
0: ['author', 'a.foo'],
},
},
atext: {
text: 'foo\n',
attribs: '|1+4',
},
},
},
'pad:testing:revs:1': {
changeset: 'Z:4>1+1$o',
meta: {
author: 'a.foo',
timestamp: 1597632398288,
pool: {
nextNum: 1,
numToAttrib: {
0: ['author', 'a.foo'],
},
},
atext: {
text: 'fooo\n',
attribs: '*0|1+5',
},
},
},
'pad:testing:revs:2': {
changeset: 'Z:5>1+1$o',
meta: {
author: 'a.foo',
timestamp: 1597632398288,
pool: {
numToAttrib: {},
nextNum: 0,
},
atext: {
text: 'foooo\n',
attribs: '*0|1+6',
},
},
},
});
const importEtherpad = (records) => agent.post(`/p/${testPadId}/import`)
.attach('file', Buffer.from(JSON.stringify(records), 'utf8'), {
filename: '/test.etherpad',
contentType: 'application/etherpad',
});
before(async function () {
// makeGoodExport() is assumed to produce good .etherpad records. Verify that assumption so
// that a buggy makeGoodExport() doesn't cause checks to accidentally pass.
const records = makeGoodExport();
await deleteTestPad();
await importEtherpad(records)
.expect(200)
.expect('Content-Type', /json/)
.expect((res) => assert.deepEqual(res.body, {
code: 0,
message: 'ok',
data: {directDatabaseAccess: true},
}));
await agent.get(`/p/${testPadId}/export/txt`)
.expect(200)
.buffer(true).parse(superagent.parse.text)
.expect((res) => assert.equal(res.text, 'oofoo\n'));
});
it('txt request rev 1', async function () {
await agent.get(`/p/${testPadId}/1/export/txt`)
.expect(200)
.buffer(true).parse(superagent.parse.text)
.expect((res) => assert.equal(res.text, 'ofoo\n'));
});
it('txt request rev 2', async function () {
await agent.get(`/p/${testPadId}/2/export/txt`)
.expect(200)
.buffer(true).parse(superagent.parse.text)
.expect((res) => assert.equal(res.text, 'oofoo\n'));
});
it('txt request rev 1test returns rev 1', async function () {
await agent.get(`/p/${testPadId}/1test/export/txt`)
.expect(200)
.buffer(true).parse(superagent.parse.text)
.expect((res) => assert.equal(res.text, 'ofoo\n'));
});
it('txt request rev test1 is 403', async function () {
await agent.get(`/p/${testPadId}/test1/export/txt`)
.expect(500)
.buffer(true).parse(superagent.parse.text)
.expect((res) => assert.match(res.text, /rev is not a number/));
});
it('txt request rev 5 returns head rev', async function () {
await agent.get(`/p/${testPadId}/5/export/txt`)
.expect(200)
.buffer(true).parse(superagent.parse.text)
.expect((res) => assert.equal(res.text, 'oofoo\n'));
});
it('html request rev 1', async function () {
await agent.get(`/p/${testPadId}/1/export/html`)
.expect(200)
.buffer(true).parse(superagent.parse.text)
.expect((res) => assert.match(res.text, /ofoo<br>/));
});
it('html request rev 2', async function () {
await agent.get(`/p/${testPadId}/2/export/html`)
.expect(200)
.buffer(true).parse(superagent.parse.text)
.expect((res) => assert.match(res.text, /oofoo<br>/));
});
it('html request rev 1test returns rev 1', async function () {
await agent.get(`/p/${testPadId}/1test/export/html`)
.expect(200)
.buffer(true).parse(superagent.parse.text)
.expect((res) => assert.match(res.text, /ofoo<br>/));
});
it('html request rev test1 results in 500 response', async function () {
await agent.get(`/p/${testPadId}/test1/export/html`)
.expect(500)
.buffer(true).parse(superagent.parse.text)
.expect((res) => assert.match(res.text, /rev is not a number/));
});
it('html request rev 5 returns head rev', async function () {
await agent.get(`/p/${testPadId}/5/export/html`)
.expect(200)
.buffer(true).parse(superagent.parse.text)
.expect((res) => assert.match(res.text, /oofoo<br>/));
});
});
describe('Import authorization checks', function () {
let authorize;

View file

@ -77,6 +77,89 @@ 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();
}
});
it('CHANGESET_REQ: revNum 2 is converted to head rev 1 (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: '2',
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 () {