diff --git a/.github/workflows/backend-tests.yml b/.github/workflows/backend-tests.yml
index c16b79a5e..485ec0cc1 100644
--- a/.github/workflows/backend-tests.yml
+++ b/.github/workflows/backend-tests.yml
@@ -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
diff --git a/.github/workflows/frontend-admin-tests.yml b/.github/workflows/frontend-admin-tests.yml
index c10cc0d5a..57336cc76 100644
--- a/.github/workflows/frontend-admin-tests.yml
+++ b/.github/workflows/frontend-admin-tests.yml
@@ -14,7 +14,7 @@ jobs:
strategy:
fail-fast: false
matrix:
- node: [14, 16, 18]
+ node: [16, 18, 20]
steps:
-
diff --git a/.github/workflows/frontend-tests.yml b/.github/workflows/frontend-tests.yml
index 89dd72866..653ee9d60 100644
--- a/.github/workflows/frontend-tests.yml
+++ b/.github/workflows/frontend-tests.yml
@@ -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
diff --git a/.github/workflows/lint-package-lock.yml b/.github/workflows/lint-package-lock.yml
index bc05a1a52..e3401a94f 100644
--- a/.github/workflows/lint-package-lock.yml
+++ b/.github/workflows/lint-package-lock.yml
@@ -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
diff --git a/.github/workflows/load-test.yml b/.github/workflows/load-test.yml
index 9d8c4fd9b..6eb3afad7 100644
--- a/.github/workflows/load-test.yml
+++ b/.github/workflows/load-test.yml
@@ -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
diff --git a/.github/workflows/rate-limit.yml b/.github/workflows/rate-limit.yml
index 7df7aa4ce..005002b08 100644
--- a/.github/workflows/rate-limit.yml
+++ b/.github/workflows/rate-limit.yml
@@ -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
diff --git a/.github/workflows/upgrade-from-latest-release.yml b/.github/workflows/upgrade-from-latest-release.yml
index a00e9540d..69eb08d8e 100644
--- a/.github/workflows/upgrade-from-latest-release.yml
+++ b/.github/workflows/upgrade-from-latest-release.yml
@@ -18,7 +18,7 @@ jobs:
strategy:
fail-fast: false
matrix:
- node: [14, 16, 18]
+ node: [16, 18, 20]
steps:
-
name: Check out latest release
diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml
index bcd8532a3..53fe33d07 100644
--- a/.github/workflows/windows.yml
+++ b/.github/workflows/windows.yml
@@ -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
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 524899dc0..e82d99ed8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -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
diff --git a/README.md b/README.md
index b798fda60..3af3df511 100644
--- a/README.md
+++ b/README.md
@@ -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
diff --git a/src/node/db/API.js b/src/node/db/API.js
index 9b2ecadc7..3f92c47dd 100644
--- a/src/node/db/API.js
+++ b/src/node/db/API.js
@@ -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
diff --git a/src/node/db/Pad.js b/src/node/db/Pad.js
index b692962f1..a9c87541f 100644
--- a/src/node/db/Pad.js
+++ b/src/node/db/Pad.js
@@ -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(
diff --git a/src/node/handler/ExportHandler.js b/src/node/handler/ExportHandler.js
index f3fde047c..417380866 100644
--- a/src/node/handler/ExportHandler.js
+++ b/src/node/handler/ExportHandler.js
@@ -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') {
diff --git a/src/node/handler/PadMessageHandler.js b/src/node/handler/PadMessageHandler.js
index 9a1885b73..35c76b5d9 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,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});
diff --git a/src/node/utils/ExportHelper.js b/src/node/utils/ExportHelper.js
index 7962476e8..48054e7f4 100644
--- a/src/node/utils/ExportHelper.js
+++ b/src/node/utils/ExportHelper.js
@@ -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;
diff --git a/src/node/utils/checkValidRev.js b/src/node/utils/checkValidRev.js
new file mode 100644
index 000000000..862c6a2bd
--- /dev/null
+++ b/src/node/utils/checkValidRev.js
@@ -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;
diff --git a/src/package-lock.json b/src/package-lock.json
index 690fca664..3d425b6d7 100644
--- a/src/package-lock.json
+++ b/src/package-lock.json
@@ -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": {
diff --git a/src/package.json b/src/package.json
index e49284d01..c1efcdee1 100644
--- a/src/package.json
+++ b/src/package.json
@@ -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": {
diff --git a/src/tests/backend/specs/api/importexportGetPost.js b/src/tests/backend/specs/api/importexportGetPost.js
index e90f7c71e..e69f0d120 100644
--- a/src/tests/backend/specs/api/importexportGetPost.js
+++ b/src/tests/backend/specs/api/importexportGetPost.js
@@ -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
/));
+ });
+
+ 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
/));
+ });
+
+ 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
/));
+ });
+
+ 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
/));
+ });
+ });
+
describe('Import authorization checks', function () {
let authorize;
diff --git a/src/tests/backend/specs/messages.js b/src/tests/backend/specs/messages.js
index bccb2584d..643005f12 100644
--- a/src/tests/backend/specs/messages.js
+++ b/src/tests/backend/specs/messages.js
@@ -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 () {