PadMessageHandler: Pass session info to `handleMessageSecurity` hook
parent
1b52c9f0c4
commit
31b025bd9d
|
@ -32,6 +32,9 @@
|
||||||
(low-level API) and `ep_etherpad-lite/static/js/AttributeMap` (high-level
|
(low-level API) and `ep_etherpad-lite/static/js/AttributeMap` (high-level
|
||||||
API).
|
API).
|
||||||
* The `import` server-side hook has a new `ImportError` context property.
|
* The `import` server-side hook has a new `ImportError` context property.
|
||||||
|
* The `handleMessageSecurity` and `handleMessage` server-side hooks have a new
|
||||||
|
`sessionInfo` context property that includes the user's author ID, the pad ID,
|
||||||
|
and whether the user only has read-only access.
|
||||||
|
|
||||||
### Compatibility changes
|
### Compatibility changes
|
||||||
|
|
||||||
|
|
|
@ -585,6 +585,12 @@ then the message will not be subject to further processing.
|
||||||
Context properties:
|
Context properties:
|
||||||
|
|
||||||
* `message`: The message being handled.
|
* `message`: The message being handled.
|
||||||
|
* `sessionInfo`: Object describing the socket.io session with the following
|
||||||
|
properties:
|
||||||
|
* `authorId`: The user's author ID.
|
||||||
|
* `padId`: The real (not read-only) ID of the pad.
|
||||||
|
* `readOnly`: Whether the client has read-only access (true) or read/write
|
||||||
|
access (false).
|
||||||
* `socket`: The socket.io Socket object.
|
* `socket`: The socket.io Socket object.
|
||||||
* `client`: (**Deprecated**; use `socket` instead.) Synonym of `socket`.
|
* `client`: (**Deprecated**; use `socket` instead.) Synonym of `socket`.
|
||||||
|
|
||||||
|
@ -620,13 +626,21 @@ Supported return values:
|
||||||
Context properties:
|
Context properties:
|
||||||
|
|
||||||
* `message`: The message being handled.
|
* `message`: The message being handled.
|
||||||
|
* `sessionInfo`: Object describing the socket.io connection with the following
|
||||||
|
properties:
|
||||||
|
* `authorId`: The user's author ID.
|
||||||
|
* `padId`: The real (not read-only) ID of the pad.
|
||||||
|
* `readOnly`: Whether the client has read-only access (true) or read/write
|
||||||
|
access (false).
|
||||||
* `socket`: The socket.io Socket object.
|
* `socket`: The socket.io Socket object.
|
||||||
* `client`: (**Deprecated**; use `socket` instead.) Synonym of `socket`.
|
* `client`: (**Deprecated**; use `socket` instead.) Synonym of `socket`.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
exports.handleMessageSecurity = async (hookName, {message, socket}) => {
|
exports.handleMessageSecurity = async (hookName, context) => {
|
||||||
|
const {message, sessionInfo: {readOnly}, socket} = context;
|
||||||
|
if (!readOnly || message.type !== 'COLLABROOM') return;
|
||||||
if (shouldGrantWriteAccess(message, socket)) return true;
|
if (shouldGrantWriteAccess(message, socket)) return true;
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
|
@ -235,6 +235,11 @@ exports.handleMessage = async (socket, message) => {
|
||||||
padID: message.padId,
|
padID: message.padId,
|
||||||
token: message.token,
|
token: message.token,
|
||||||
};
|
};
|
||||||
|
const padIds = await readOnlyManager.getIds(thisSession.auth.padID);
|
||||||
|
thisSession.padId = padIds.padId;
|
||||||
|
thisSession.readOnlyPadId = padIds.readOnlyPadId;
|
||||||
|
thisSession.readonly =
|
||||||
|
padIds.readonly || !webaccess.userCanModify(thisSession.auth.padID, socket.client.request);
|
||||||
}
|
}
|
||||||
|
|
||||||
const auth = thisSession.auth;
|
const auth = thisSession.auth;
|
||||||
|
@ -273,6 +278,11 @@ exports.handleMessage = async (socket, message) => {
|
||||||
// Allow plugins to bypass the readonly message blocker
|
// Allow plugins to bypass the readonly message blocker
|
||||||
const context = {
|
const context = {
|
||||||
message,
|
message,
|
||||||
|
sessionInfo: {
|
||||||
|
authorId: thisSession.author,
|
||||||
|
padId: thisSession.padId,
|
||||||
|
readOnly: thisSession.readonly,
|
||||||
|
},
|
||||||
socket,
|
socket,
|
||||||
get client() {
|
get client() {
|
||||||
padutils.warnDeprecated(
|
padutils.warnDeprecated(
|
||||||
|
@ -793,12 +803,6 @@ const handleClientReady = async (socket, message) => {
|
||||||
if (sessionInfo == null) return;
|
if (sessionInfo == null) return;
|
||||||
assert(sessionInfo.author);
|
assert(sessionInfo.author);
|
||||||
|
|
||||||
const padIds = await readOnlyManager.getIds(sessionInfo.auth.padID);
|
|
||||||
sessionInfo.padId = padIds.padId;
|
|
||||||
sessionInfo.readOnlyPadId = padIds.readOnlyPadId;
|
|
||||||
sessionInfo.readonly =
|
|
||||||
padIds.readonly || !webaccess.userCanModify(sessionInfo.auth.padID, socket.client.request);
|
|
||||||
|
|
||||||
await hooks.aCallAll('clientReady', message); // Deprecated due to awkward context.
|
await hooks.aCallAll('clientReady', message); // Deprecated due to awkward context.
|
||||||
|
|
||||||
let {colorId: authorColorId, name: authorName} = message.userInfo || {};
|
let {colorId: authorColorId, name: authorName} = message.userInfo || {};
|
||||||
|
|
|
@ -36,12 +36,10 @@ exports.userCanModify = (padId, req) => {
|
||||||
if (readOnlyManager.isReadOnlyId(padId)) return false;
|
if (readOnlyManager.isReadOnlyId(padId)) return false;
|
||||||
if (!settings.requireAuthentication) return true;
|
if (!settings.requireAuthentication) return true;
|
||||||
const {session: {user} = {}} = req;
|
const {session: {user} = {}} = req;
|
||||||
assert(user); // If authn required and user == null, the request should have already been denied.
|
if (!user || user.readOnly) return false;
|
||||||
if (user.readOnly) return false;
|
|
||||||
assert(user.padAuthorizations); // This is populated even if !settings.requireAuthorization.
|
assert(user.padAuthorizations); // This is populated even if !settings.requireAuthorization.
|
||||||
const level = exports.normalizeAuthzLevel(user.padAuthorizations[padId]);
|
const level = exports.normalizeAuthzLevel(user.padAuthorizations[padId]);
|
||||||
assert(level); // If !level, the request should have already been denied.
|
return level && level !== 'readOnly';
|
||||||
return level !== 'readOnly';
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Exported so that tests can set this to 0 to avoid unnecessary test slowness.
|
// Exported so that tests can set this to 0 to avoid unnecessary test slowness.
|
||||||
|
|
Loading…
Reference in New Issue