feat(backend): main handling of readonly sharing

* Saving works as before
* Don't broadcast drawevents from readonly whiteboard (prevents malicious use)
This commit is contained in:
Florent Chehab 2020-05-12 21:32:46 +02:00
parent d268eb6d93
commit 14e1ee5391
No known key found for this signature in database
GPG Key ID: 9A0CE018889EA246
2 changed files with 100 additions and 7 deletions

View File

@ -2,6 +2,7 @@ const path = require("path");
const config = require("./config/config");
const WhiteboardServerSideInfo = require("./WhiteboardServerSideInfo");
const ReadOnlyBackendService = require("./services/ReadOnlyBackendService");
function startBackendServer(port) {
var fs = require("fs-extra");
@ -28,10 +29,13 @@ function startBackendServer(port) {
const { accessToken, enableWebdav } = config.backend;
app.get("/api/loadwhiteboard", function (req, res) {
var wid = req["query"]["wid"];
var at = req["query"]["at"]; //accesstoken
const wid = req["query"]["wid"];
const at = req["query"]["at"]; //accesstoken
if (accessToken === "" || accessToken == at) {
var ret = s_whiteboard.loadStoredData(wid);
const widForData = ReadOnlyBackendService.isReadOnly(wid)
? ReadOnlyBackendService.getIdFromReadOnlyId(wid)
: wid;
const ret = s_whiteboard.loadStoredData(widForData);
res.send(ret);
res.end();
} else {
@ -192,7 +196,7 @@ function startBackendServer(port) {
}, (1 / config.backend.performance.whiteboardInfoBroadcastFreq) * 1000);
io.on("connection", function (socket) {
var whiteboardId = null;
let whiteboardId = null;
socket.on("disconnect", function () {
if (infoByWhiteboard.has(whiteboardId)) {
const whiteboardServerSideInfo = infoByWhiteboard.get(whiteboardId);
@ -212,9 +216,20 @@ function startBackendServer(port) {
});
socket.on("drawToWhiteboard", function (content) {
if (!whiteboardId || ReadOnlyBackendService.isReadOnly(whiteboardId)) return;
content = escapeAllContentStrings(content);
if (accessToken === "" || accessToken == content["at"]) {
socket.compress(false).broadcast.to(whiteboardId).emit("drawToWhiteboard", content); //Send to all users in the room (not own socket)
const broadcastTo = (wid) =>
socket.compress(false).broadcast.to(wid).emit("drawToWhiteboard", content);
// broadcast to current whiteboard
broadcastTo(whiteboardId);
const readOnlyId = ReadOnlyBackendService.getReadOnlyId(whiteboardId);
const readOnlyWhiteboardInfo = infoByWhiteboard.get(readOnlyId);
if (readOnlyWhiteboardInfo && readOnlyWhiteboardInfo.hasConnectedUser()) {
// broadcast the same content to the associated read-only whiteboard
broadcastTo(readOnlyId);
}
s_whiteboard.handleEventsAndData(content); //save whiteboardchanges on the server
} else {
socket.emit("wrongAccessToken", true);
@ -224,9 +239,16 @@ function startBackendServer(port) {
socket.on("joinWhiteboard", function (content) {
content = escapeAllContentStrings(content);
if (accessToken === "" || accessToken == content["at"]) {
socket.emit("whiteboardConfig", { common: config.frontend });
whiteboardId = content["wid"];
socket.emit("whiteboardConfig", {
common: config.frontend,
whiteboardSpecific: {
correspondingReadOnlyId: ReadOnlyBackendService.getReadOnlyId(whiteboardId),
isReadOnly: ReadOnlyBackendService.isReadOnly(whiteboardId),
},
});
socket.join(whiteboardId); //Joins room name=wid
if (!infoByWhiteboard.has(whiteboardId)) {
infoByWhiteboard.set(whiteboardId, new WhiteboardServerSideInfo());

View File

@ -0,0 +1,71 @@
const { v4: uuidv4 } = require("uuid");
class ReadOnlyBackendService {
/**
* Mapping from an editable whiteboard id to the matching read-only whiteboard id
* @type {Map<string, string>}
* @private
*/
#idToReadOnlyId = new Map();
/**
* Mapping from a read-only whiteboard id to the matching editable whiteboard id
*
* @type {Map<string, string>}
* @private
*/
#readOnlyIdToId = new Map();
/**
* Make sure a whiteboardId is ignited in the service
*
* If it's not found in the service, we assume that it's an editable whiteboard
*
* @param {string} whiteboardId
*/
init(whiteboardId) {
const idToReadOnlyId = this.#idToReadOnlyId;
const readOnlyIdToId = this.#readOnlyIdToId;
if (!idToReadOnlyId.has(whiteboardId) && !readOnlyIdToId.has(whiteboardId)) {
const readOnlyId = uuidv4();
idToReadOnlyId.set(whiteboardId, readOnlyId);
readOnlyIdToId.set(readOnlyId, whiteboardId);
}
}
/**
* Get the read-only id corresponding to a whiteboard id
*
* @param {string} whiteboardId
* @return {string}
*/
getReadOnlyId(whiteboardId) {
// make sure it's inited
this.init(whiteboardId);
return this.#idToReadOnlyId.get(whiteboardId);
}
/**
* Get the id corresponding to readonly id
*
* @param {string} readOnlyId
* @return {string}
*/
getIdFromReadOnlyId(readOnlyId) {
return this.#readOnlyIdToId.get(readOnlyId);
}
/**
* Tell is whiteboard id corresponds to a read-only whiteboard
*
* @param whiteboardId
* @return {boolean}
*/
isReadOnly(whiteboardId) {
this.init(whiteboardId);
return this.#readOnlyIdToId.has(whiteboardId);
}
}
module.exports = new ReadOnlyBackendService();