mirror of
https://github.com/ether/etherpad-lite.git
synced 2025-04-21 07:56:16 -04:00
SecurityManager: Refactor checkAccess for readability, correctness
* Move session validity check and session author ID fetch to a separate function. This separate function can be used by hooks, making it easier for them to properly determine the author ID. * Rewrite the remainder of checkAccess. Benefits: - The function is more readable and maintainable now. - Vulnerability fix: Before, the session IDs in sessionCookie were not validated when checking settings.requireSession. Now, sessionCookie must identify a valid session for the settings.requireSession test to pass. - Bug fix: Before, checkAccess would sometimes use the author ID associated with the token even if sessionCookie identified a valid session. Now it always uses the author ID associated with the session if available.
This commit is contained in:
parent
8756fed80d
commit
8b0baa9679
3 changed files with 136 additions and 210 deletions
|
@ -2,7 +2,40 @@
|
|||
* Helpers to manipulate promises (like async but for promises).
|
||||
*/
|
||||
|
||||
var timesLimit = function (ltMax, concurrency, promiseCreator) {
|
||||
// Returns a Promise that resolves to the first resolved value from `promises` that satisfies
|
||||
// `predicate`. Resolves to `undefined` if none of the Promises satisfy `predicate`, or if
|
||||
// `promises` is empty. If `predicate` is nullish, the truthiness of the resolved value is used as
|
||||
// the predicate.
|
||||
exports.firstSatisfies = (promises, predicate) => {
|
||||
if (predicate == null) predicate = (x) => x;
|
||||
|
||||
// Transform each original Promise into a Promise that never resolves if the original resolved
|
||||
// value does not satisfy `predicate`. These transformed Promises will be passed to Promise.race,
|
||||
// yielding the first resolved value that satisfies `predicate`.
|
||||
const newPromises = promises.map(
|
||||
(p) => new Promise((resolve, reject) => p.then((v) => predicate(v) && resolve(v), reject)));
|
||||
|
||||
// If `promises` is an empty array or if none of them resolve to a value that satisfies
|
||||
// `predicate`, then `Promise.race(newPromises)` will never resolve. To handle that, add another
|
||||
// Promise that resolves to `undefined` after all of the original Promises resolve.
|
||||
//
|
||||
// Note: If all of the original Promises simultaneously resolve to a value that satisfies
|
||||
// `predicate` (perhaps they were already resolved when this function was called), then this
|
||||
// Promise will resolve too, and with a value of `undefined`. There is no concern that this
|
||||
// Promise will win the race and thus cause an erroneous `undefined` result. This is because
|
||||
// a resolved Promise's `.then()` function is scheduled for execution -- not executed right away
|
||||
// -- and ES guarantees in-order execution of the enqueued invocations. Each of the above
|
||||
// transformed Promises has a `.then()` chain of length one, while the Promise added here has a
|
||||
// `.then()` chain of length two or more (at least one `.then()` that is internal to
|
||||
// `Promise.all()`, plus the `.then()` function added here). By the time the `.then()` function
|
||||
// added here executes, all of the above transformed Promises will have already resolved and one
|
||||
// will have been chosen as the winner.
|
||||
newPromises.push(Promise.all(promises).then(() => {}));
|
||||
|
||||
return Promise.race(newPromises);
|
||||
};
|
||||
|
||||
exports.timesLimit = function(ltMax, concurrency, promiseCreator) {
|
||||
var done = 0
|
||||
var current = 0
|
||||
|
||||
|
@ -26,7 +59,3 @@ var timesLimit = function (ltMax, concurrency, promiseCreator) {
|
|||
addAnother()
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
timesLimit: timesLimit
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue