diff --git a/.github/workflows/frontend-tests.yml b/.github/workflows/frontend-tests.yml
index 1b57f651..6be1d852 100644
--- a/.github/workflows/frontend-tests.yml
+++ b/.github/workflows/frontend-tests.yml
@@ -78,6 +78,7 @@ jobs:
ep_align
ep_author_hover
ep_cursortrace
+ ep_embedmedia
ep_font_size
ep_hash_auth
ep_headings2
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 906212a5..331a1b98 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,12 @@
+# 1.8.12
+
+### Notable fixes
+
+* Fixed a bug in the `dirty` database driver that sometimes caused Node.js to
+ crash during shutdown and lose buffered database writes.
+* Fixed a regression in v1.8.8 that caused "Uncaught TypeError: Cannot read
+ property '0' of undefined" with some plugins (#4885)
+
# 1.8.11
### Notable fixes
diff --git a/README.md b/README.md
index 02eeac3f..a196c719 100644
--- a/README.md
+++ b/README.md
@@ -26,7 +26,7 @@ Etherpad is extremely flexible providing you the means to modify it to solve wha
[![Frontend admin tests](https://github.com/ether/etherpad-lite/actions/workflows/frontend-admin-tests.yml/badge.svg?color=%2344b492)](https://github.com/ether/etherpad-lite/actions/workflows/frontend-admin-tests.yml) [![Frontend tests](https://github.com/ether/etherpad-lite/actions/workflows/frontend-tests.yml/badge.svg?color=%2344b492)](https://github.com/ether/etherpad-lite/actions/workflows/frontend-tests.yml) [![Windows Installer](https://github.com/ether/etherpad-lite/actions/workflows/windows-installer.yml/badge.svg?color=%2344b492)](https://github.com/ether/etherpad-lite/actions/workflows/windows-installer.yml)
### Engagement
- ![Discord](https://img.shields.io/discord/741309013593030667?color=%2344b492) ![Etherpad plugins](https://img.shields.io/endpoint?url=https%3A%2F%2Fstatic.etherpad.org%2Fshields.json&color=%2344b492 "Etherpad plugins") ![Languages](https://img.shields.io/static/v1?label=Languages&message=105&color=%2344b492) ![Translation Coverage](https://img.shields.io/static/v1?label=Languages&message=98%&color=%2344b492)
+ [![Discord](https://img.shields.io/discord/741309013593030667?color=%2344b492)](https://discord.com/invite/daEjfhw) [![Etherpad plugins](https://img.shields.io/endpoint?url=https%3A%2F%2Fstatic.etherpad.org%2Fshields.json&color=%2344b492 "Etherpad plugins")](https://static.etherpad.org/index.html) ![Languages](https://img.shields.io/static/v1?label=Languages&message=105&color=%2344b492) ![Translation Coverage](https://img.shields.io/static/v1?label=Languages&message=98%&color=%2344b492)
# Installation
diff --git a/src/node/hooks/express/padurlsanitize.js b/src/node/hooks/express/padurlsanitize.js
index 30297479..b805fc4b 100644
--- a/src/node/hooks/express/padurlsanitize.js
+++ b/src/node/hooks/express/padurlsanitize.js
@@ -18,7 +18,7 @@ exports.expressCreateServer = (hookName, args, cb) => {
next();
} else {
// the pad id was sanitized, so we redirect to the sanitized version
- const realURL = encodeURIComponent(sanitizedPadId) + new URL(req.url).search;
+ const realURL = encodeURIComponent(sanitizedPadId) + new URL(req.url, 'http://invalid.invalid').search;
res.header('Location', realURL);
res.status(302).send(`You should be redirected to ${realURL}`);
}
diff --git a/src/node/utils/Minify.js b/src/node/utils/Minify.js
index 4874432b..f4826021 100644
--- a/src/node/utils/Minify.js
+++ b/src/node/utils/Minify.js
@@ -123,6 +123,15 @@ const sanitizePathname = (p) => {
return p;
};
+const compatPaths = {
+ 'js/browser.js': 'js/vendors/browser.js',
+ 'js/farbtastic.js': 'js/vendors/farbtastic.js',
+ 'js/gritter.js': 'js/vendors/gritter.js',
+ 'js/html10n.js': 'js/vendors/html10n.js',
+ 'js/jquery.js': 'js/vendors/jquery.js',
+ 'js/nice-select.js': 'js/vendors/nice-select.js',
+};
+
/**
* creates the minifed javascript for the given minified name
* @param req the Express request
@@ -139,11 +148,11 @@ const minify = async (req, res) => {
return;
}
- // Backward compatibility for plugins that were written when jQuery lived at
- // src/static/js/jquery.js.
- if (['js/jquery.js', 'plugins/ep_etherpad-lite/static/js/jquery.js'].indexOf(filename) !== -1) {
- logger.warn(`request for deprecated jQuery path: ${filename}`);
- filename = 'js/vendors/jquery.js';
+ // Backward compatibility for plugins that require() files from old paths.
+ const newLocation = compatPaths[filename.replace(/^plugins\/ep_etherpad-lite\/static\//, '')];
+ if (newLocation != null) {
+ logger.warn(`request for deprecated path "${filename}", replacing with "${newLocation}"`);
+ filename = newLocation;
}
/* Handle static files for plugins/libraries:
diff --git a/src/package-lock.json b/src/package-lock.json
index f22457e1..26c65378 100644
--- a/src/package-lock.json
+++ b/src/package-lock.json
@@ -1413,9 +1413,9 @@
"dev": true
},
"dirty": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/dirty/-/dirty-1.1.0.tgz",
- "integrity": "sha1-cO3SuZlUHcmXT9Ooy9DGcP4jYHg="
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/dirty/-/dirty-1.1.1.tgz",
+ "integrity": "sha512-l/SMZcT+MjqOPpjarzJ8nQdxtxurURJM7js1l0Q2TQWtNbPzDYzkK++HlbT+XmM+adPFNdb3SOlVz9Jr7Df7xQ=="
},
"doctrine": {
"version": "3.0.0",
@@ -8419,14 +8419,14 @@
}
},
"ueberdb2": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/ueberdb2/-/ueberdb2-1.3.1.tgz",
- "integrity": "sha512-uhUSJfI5sNWdiXxae0kOg88scaMIKcV0CVeojwPQzgm93vQVuGyCqS1g1i3gTZel6SwmXRFtYtfmtAmiEe+HBQ==",
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/ueberdb2/-/ueberdb2-1.3.2.tgz",
+ "integrity": "sha512-7Ub5jDsIS+qjjsNV7yp1CHXHVe2K9ZUpwaHi9BZf3ai0DxtuHOfMada1wxL6iyEjwYXh/Nsu80iyId51wHFf4A==",
"requires": {
"async": "^3.2.0",
"cassandra-driver": "^4.5.1",
"channels": "0.0.4",
- "dirty": "^1.1.0",
+ "dirty": "^1.1.1",
"elasticsearch": "^16.7.1",
"mongodb": "^3.6.3",
"mssql": "^7.0.0-beta.2",
diff --git a/src/package.json b/src/package.json
index 6f3e5161..1a0eb74d 100644
--- a/src/package.json
+++ b/src/package.json
@@ -69,7 +69,7 @@
"threads": "^1.4.0",
"tiny-worker": "^2.3.0",
"tinycon": "0.6.8",
- "ueberdb2": "^1.3.1",
+ "ueberdb2": "^1.3.2",
"underscore": "1.12.0",
"unorm": "1.6.0",
"wtfnode": "^0.8.4"
diff --git a/src/static/js/ace2_inner.js b/src/static/js/ace2_inner.js
index 4858aa1b..5ae4f066 100644
--- a/src/static/js/ace2_inner.js
+++ b/src/static/js/ace2_inner.js
@@ -3894,7 +3894,7 @@ function Ace2Inner() {
documentAttributeManager = new AttributeManager(rep, performDocumentApplyChangeset);
editorInfo.ace_performDocumentApplyAttributesToRange =
- (...args) => documentAttributeManager.setAttributesOnRange(args);
+ (...args) => documentAttributeManager.setAttributesOnRange(...args);
this.init = () => {
$(document).ready(() => {
diff --git a/src/tests/backend/specs/pads-with-spaces.js b/src/tests/backend/specs/pads-with-spaces.js
new file mode 100644
index 00000000..0db99865
--- /dev/null
+++ b/src/tests/backend/specs/pads-with-spaces.js
@@ -0,0 +1,24 @@
+'use strict';
+
+const common = require('../common');
+const assert = require('../assert-legacy').strict;
+
+let agent;
+
+describe(__filename, function () {
+ before(async function () {
+ agent = await common.init();
+ });
+
+ it('supports pads with spaces, regression test for #4883', async function () {
+ await agent.get('/p/pads with spaces')
+ .expect(302)
+ .expect('location', 'pads_with_spaces');
+ });
+
+ it('supports pads with spaces and query, regression test for #4883', async function () {
+ await agent.get('/p/pads with spaces?showChat=true&noColors=false')
+ .expect(302)
+ .expect('location', 'pads_with_spaces?showChat=true&noColors=false');
+ });
+});