mirror of
https://github.com/ether/etherpad-lite.git
synced 2025-01-31 19:02:59 +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": {},
|
"customLocaleStrings": {},
|
||||||
|
|
||||||
/* Disable Admin UI tests */
|
/* 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": {},
|
"customLocaleStrings": {},
|
||||||
|
|
||||||
/* Disable Admin UI tests */
|
/* 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 CustomError = require('../utils/customError');
|
||||||
const Pad = require('../db/Pad');
|
const Pad = require('../db/Pad');
|
||||||
const db = require('./DB');
|
const db = require('./DB');
|
||||||
|
const settings = require('../utils/Settings');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A cache of all loaded Pads.
|
* A cache of all loaded Pads.
|
||||||
|
@ -170,6 +171,8 @@ exports.sanitizePadId = async (padId) => {
|
||||||
padId = padId.replace(from, to);
|
padId = padId.replace(from, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (settings.lowerCasePadIds) padId = padId.toLowerCase();
|
||||||
|
|
||||||
// we're out of possible transformations, so just return it
|
// we're out of possible transformations, so just return it
|
||||||
return padId;
|
return padId;
|
||||||
};
|
};
|
||||||
|
|
|
@ -236,6 +236,11 @@ exports.handleMessage = async (socket, message) => {
|
||||||
padID: message.padId,
|
padID: message.padId,
|
||||||
token: message.token,
|
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);
|
const padIds = await readOnlyManager.getIds(thisSession.auth.padID);
|
||||||
thisSession.padId = padIds.padId;
|
thisSession.padId = padIds.padId;
|
||||||
thisSession.readOnlyPadId = padIds.readOnlyPadId;
|
thisSession.readOnlyPadId = padIds.readOnlyPadId;
|
||||||
|
|
|
@ -430,6 +430,11 @@ exports.importMaxFileSize = 50 * 1024 * 1024;
|
||||||
*/
|
*/
|
||||||
exports.enableAdminUITests = false;
|
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
|
// checks if abiword is avaiable
|
||||||
exports.abiwordAvailable = () => {
|
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.padOuter$.fx.off = true;
|
||||||
helper.padInner$.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) => {
|
helper.newAdmin = async (page) => {
|
||||||
|
|
|
@ -175,9 +175,8 @@ helper.disableStickyChatviaIcon = async () => {
|
||||||
*/
|
*/
|
||||||
helper.gotoTimeslider = async (revision) => {
|
helper.gotoTimeslider = async (revision) => {
|
||||||
revision = Number.isInteger(revision) ? `#${revision}` : '';
|
revision = Number.isInteger(revision) ? `#${revision}` : '';
|
||||||
const iframe = $('#iframe-container iframe');
|
helper.padChrome$.window.location.href =
|
||||||
iframe.attr('src', `${iframe.attr('src')}/timeslider${revision}`);
|
`${helper.padChrome$.window.location.pathname}/timeslider${revision}`;
|
||||||
|
|
||||||
await helper.waitForPromise(() => helper.timesliderTimerTime() &&
|
await helper.waitForPromise(() => helper.timesliderTimerTime() &&
|
||||||
!Number.isNaN(new Date(helper.timesliderTimerTime()).getTime()), 10000);
|
!Number.isNaN(new Date(helper.timesliderTimerTime()).getTime()), 10000);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue