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:
parent
d268eb6d93
commit
14e1ee5391
@ -2,6 +2,7 @@ const path = require("path");
|
|||||||
|
|
||||||
const config = require("./config/config");
|
const config = require("./config/config");
|
||||||
const WhiteboardServerSideInfo = require("./WhiteboardServerSideInfo");
|
const WhiteboardServerSideInfo = require("./WhiteboardServerSideInfo");
|
||||||
|
const ReadOnlyBackendService = require("./services/ReadOnlyBackendService");
|
||||||
|
|
||||||
function startBackendServer(port) {
|
function startBackendServer(port) {
|
||||||
var fs = require("fs-extra");
|
var fs = require("fs-extra");
|
||||||
@ -28,10 +29,13 @@ function startBackendServer(port) {
|
|||||||
const { accessToken, enableWebdav } = config.backend;
|
const { accessToken, enableWebdav } = config.backend;
|
||||||
|
|
||||||
app.get("/api/loadwhiteboard", function (req, res) {
|
app.get("/api/loadwhiteboard", function (req, res) {
|
||||||
var wid = req["query"]["wid"];
|
const wid = req["query"]["wid"];
|
||||||
var at = req["query"]["at"]; //accesstoken
|
const at = req["query"]["at"]; //accesstoken
|
||||||
if (accessToken === "" || accessToken == at) {
|
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.send(ret);
|
||||||
res.end();
|
res.end();
|
||||||
} else {
|
} else {
|
||||||
@ -192,7 +196,7 @@ function startBackendServer(port) {
|
|||||||
}, (1 / config.backend.performance.whiteboardInfoBroadcastFreq) * 1000);
|
}, (1 / config.backend.performance.whiteboardInfoBroadcastFreq) * 1000);
|
||||||
|
|
||||||
io.on("connection", function (socket) {
|
io.on("connection", function (socket) {
|
||||||
var whiteboardId = null;
|
let whiteboardId = null;
|
||||||
socket.on("disconnect", function () {
|
socket.on("disconnect", function () {
|
||||||
if (infoByWhiteboard.has(whiteboardId)) {
|
if (infoByWhiteboard.has(whiteboardId)) {
|
||||||
const whiteboardServerSideInfo = infoByWhiteboard.get(whiteboardId);
|
const whiteboardServerSideInfo = infoByWhiteboard.get(whiteboardId);
|
||||||
@ -212,9 +216,20 @@ function startBackendServer(port) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
socket.on("drawToWhiteboard", function (content) {
|
socket.on("drawToWhiteboard", function (content) {
|
||||||
|
if (!whiteboardId || ReadOnlyBackendService.isReadOnly(whiteboardId)) return;
|
||||||
|
|
||||||
content = escapeAllContentStrings(content);
|
content = escapeAllContentStrings(content);
|
||||||
if (accessToken === "" || accessToken == content["at"]) {
|
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
|
s_whiteboard.handleEventsAndData(content); //save whiteboardchanges on the server
|
||||||
} else {
|
} else {
|
||||||
socket.emit("wrongAccessToken", true);
|
socket.emit("wrongAccessToken", true);
|
||||||
@ -224,9 +239,16 @@ function startBackendServer(port) {
|
|||||||
socket.on("joinWhiteboard", function (content) {
|
socket.on("joinWhiteboard", function (content) {
|
||||||
content = escapeAllContentStrings(content);
|
content = escapeAllContentStrings(content);
|
||||||
if (accessToken === "" || accessToken == content["at"]) {
|
if (accessToken === "" || accessToken == content["at"]) {
|
||||||
socket.emit("whiteboardConfig", { common: config.frontend });
|
|
||||||
|
|
||||||
whiteboardId = content["wid"];
|
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
|
socket.join(whiteboardId); //Joins room name=wid
|
||||||
if (!infoByWhiteboard.has(whiteboardId)) {
|
if (!infoByWhiteboard.has(whiteboardId)) {
|
||||||
infoByWhiteboard.set(whiteboardId, new WhiteboardServerSideInfo());
|
infoByWhiteboard.set(whiteboardId, new WhiteboardServerSideInfo());
|
||||||
|
71
scripts/services/ReadOnlyBackendService.js
Normal file
71
scripts/services/ReadOnlyBackendService.js
Normal 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();
|
Loading…
Reference in New Issue
Block a user