mirror of
https://github.com/ether/etherpad-lite.git
synced 2025-01-19 06:03:34 +01:00
allow option to make pad names case-insensitive (#5501) by @DanielHabenicht
* New option to make pad names case-insensitive fixes #3844 * fix helper.gotoTimeslider() * fix helper.aNewPad() return value * Update src/node/utils/Settings.js Co-authored-by: Richard Hansen <rhansen@rhansen.org> * remove timeout * rename enforceLowerCasePadIds to lowerCasePadIds * use before and after hooks * update with socket specific test * enforce sanitizing padID for websocket connections - only enforce for newly created pads, to combat case-sensitive pad name hijacking * Added updated package.json file. --------- Co-authored-by: Richard Hansen <rhansen@rhansen.org> Co-authored-by: SamTV12345 <40429738+samtv12345@users.noreply.github.com>
This commit is contained in:
parent
22704f7dff
commit
675c0130b9
9 changed files with 950 additions and 858 deletions
|
@ -634,5 +634,10 @@
|
|||
"customLocaleStrings": {},
|
||||
|
||||
/* Disable Admin UI tests */
|
||||
"enableAdminUITests": false
|
||||
"enableAdminUITests": false,
|
||||
|
||||
/*
|
||||
* Enable/Disable case-insensitive pad names.
|
||||
*/
|
||||
"lowerCasePadIds": "${LOWER_CASE_PAD_IDS:false}"
|
||||
}
|
||||
|
|
|
@ -635,5 +635,10 @@
|
|||
"customLocaleStrings": {},
|
||||
|
||||
/* Disable Admin UI tests */
|
||||
"enableAdminUITests": false
|
||||
"enableAdminUITests": false,
|
||||
|
||||
/*
|
||||
* Enable/Disable case-insensitive pad names.
|
||||
*/
|
||||
"lowerCasePadIds": false
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
const CustomError = require('../utils/customError');
|
||||
const Pad = require('../db/Pad');
|
||||
const db = require('./DB');
|
||||
const settings = require('../utils/Settings');
|
||||
|
||||
/**
|
||||
* A cache of all loaded Pads.
|
||||
|
@ -170,6 +171,8 @@ exports.sanitizePadId = async (padId) => {
|
|||
padId = padId.replace(from, to);
|
||||
}
|
||||
|
||||
if (settings.lowerCasePadIds) padId = padId.toLowerCase();
|
||||
|
||||
// we're out of possible transformations, so just return it
|
||||
return padId;
|
||||
};
|
||||
|
|
|
@ -236,6 +236,11 @@ exports.handleMessage = async (socket, message) => {
|
|||
padID: message.padId,
|
||||
token: message.token,
|
||||
};
|
||||
|
||||
// Pad does not exist, so we need to sanitize the id
|
||||
if (!(await padManager.doesPadExist(thisSession.auth.padID))) {
|
||||
thisSession.auth.padID = await padManager.sanitizePadId(thisSession.auth.padID);
|
||||
}
|
||||
const padIds = await readOnlyManager.getIds(thisSession.auth.padID);
|
||||
thisSession.padId = padIds.padId;
|
||||
thisSession.readOnlyPadId = padIds.readOnlyPadId;
|
||||
|
|
|
@ -430,6 +430,11 @@ exports.importMaxFileSize = 50 * 1024 * 1024;
|
|||
*/
|
||||
exports.enableAdminUITests = false;
|
||||
|
||||
/*
|
||||
* Enable auto conversion of pad Ids to lowercase.
|
||||
* e.g. /p/EtHeRpAd to /p/etherpad
|
||||
*/
|
||||
exports.lowerCasePadIds = false;
|
||||
|
||||
// checks if abiword is avaiable
|
||||
exports.abiwordAvailable = () => {
|
||||
|
|
1682
src/package-lock.json
generated
1682
src/package-lock.json
generated
File diff suppressed because it is too large
Load diff
90
src/tests/backend/specs/lowerCasePadIds.js
Normal file
90
src/tests/backend/specs/lowerCasePadIds.js
Normal file
|
@ -0,0 +1,90 @@
|
|||
'use strict';
|
||||
|
||||
const assert = require('assert').strict;
|
||||
const common = require('../common');
|
||||
const padManager = require('../../../node/db/PadManager');
|
||||
const settings = require('../../../node/utils/Settings');
|
||||
|
||||
describe(__filename, function () {
|
||||
let agent;
|
||||
const cleanUpPads = async () => {
|
||||
const {padIDs} = await padManager.listAllPads();
|
||||
await Promise.all(padIDs.map(async (padId) => {
|
||||
if (await padManager.doesPadExist(padId)) {
|
||||
const pad = await padManager.getPad(padId);
|
||||
await pad.remove();
|
||||
}
|
||||
}));
|
||||
};
|
||||
let backup;
|
||||
|
||||
before(async function () {
|
||||
backup = settings.lowerCasePadIds;
|
||||
agent = await common.init();
|
||||
});
|
||||
beforeEach(async function () {
|
||||
await cleanUpPads();
|
||||
});
|
||||
afterEach(async function () {
|
||||
await cleanUpPads();
|
||||
});
|
||||
after(async function () {
|
||||
settings.lowerCasePadIds = backup;
|
||||
});
|
||||
|
||||
describe('not activated', function () {
|
||||
beforeEach(async function () {
|
||||
settings.lowerCasePadIds = false;
|
||||
});
|
||||
|
||||
|
||||
it('do nothing', async function () {
|
||||
await agent.get('/p/UPPERCASEpad')
|
||||
.expect(200);
|
||||
});
|
||||
});
|
||||
|
||||
describe('activated', function () {
|
||||
beforeEach(async function () {
|
||||
settings.lowerCasePadIds = true;
|
||||
});
|
||||
it('lowercase pad ids', async function () {
|
||||
await agent.get('/p/UPPERCASEpad')
|
||||
.expect(302)
|
||||
.expect('location', 'uppercasepad');
|
||||
});
|
||||
|
||||
it('keeps old pads accessible', async function () {
|
||||
Object.assign(settings, {
|
||||
lowerCasePadIds: false,
|
||||
});
|
||||
await padManager.getPad('ALREADYexistingPad', 'oldpad');
|
||||
await padManager.getPad('alreadyexistingpad', 'newpad');
|
||||
Object.assign(settings, {
|
||||
lowerCasePadIds: true,
|
||||
});
|
||||
|
||||
const oldPad = await agent.get('/p/ALREADYexistingPad').expect(200);
|
||||
const oldPadSocket = await common.connect(oldPad);
|
||||
const oldPadHandshake = await common.handshake(oldPadSocket, 'ALREADYexistingPad');
|
||||
assert.equal(oldPadHandshake.data.padId, 'ALREADYexistingPad');
|
||||
assert.equal(oldPadHandshake.data.collab_client_vars.initialAttributedText.text, 'oldpad\n');
|
||||
|
||||
const newPad = await agent.get('/p/alreadyexistingpad').expect(200);
|
||||
const newPadSocket = await common.connect(newPad);
|
||||
const newPadHandshake = await common.handshake(newPadSocket, 'alreadyexistingpad');
|
||||
assert.equal(newPadHandshake.data.padId, 'alreadyexistingpad');
|
||||
assert.equal(newPadHandshake.data.collab_client_vars.initialAttributedText.text, 'newpad\n');
|
||||
});
|
||||
|
||||
it('disallow creation of different case pad-name via socket connection', async function () {
|
||||
await padManager.getPad('maliciousattempt', 'attempt');
|
||||
|
||||
const newPad = await agent.get('/p/maliciousattempt').expect(200);
|
||||
const newPadSocket = await common.connect(newPad);
|
||||
const newPadHandshake = await common.handshake(newPadSocket, 'MaliciousAttempt');
|
||||
|
||||
assert.equal(newPadHandshake.data.collab_client_vars.initialAttributedText.text, 'attempt\n');
|
||||
});
|
||||
});
|
||||
});
|
|
@ -181,7 +181,9 @@ const helper = {};
|
|||
helper.padOuter$.fx.off = true;
|
||||
helper.padInner$.fx.off = true;
|
||||
|
||||
return opts.id;
|
||||
// Don't return opts.id -- the server might have redirected the browser to a transformed version
|
||||
// of the requested pad ID.
|
||||
return helper.padChrome$.window.clientVars.padId;
|
||||
};
|
||||
|
||||
helper.newAdmin = async (page) => {
|
||||
|
|
|
@ -175,9 +175,8 @@ helper.disableStickyChatviaIcon = async () => {
|
|||
*/
|
||||
helper.gotoTimeslider = async (revision) => {
|
||||
revision = Number.isInteger(revision) ? `#${revision}` : '';
|
||||
const iframe = $('#iframe-container iframe');
|
||||
iframe.attr('src', `${iframe.attr('src')}/timeslider${revision}`);
|
||||
|
||||
helper.padChrome$.window.location.href =
|
||||
`${helper.padChrome$.window.location.pathname}/timeslider${revision}`;
|
||||
await helper.waitForPromise(() => helper.timesliderTimerTime() &&
|
||||
!Number.isNaN(new Date(helper.timesliderTimerTime()).getTime()), 10000);
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue