Index: lams_build/conf/whiteboard/readme.txt
===================================================================
diff -u -r67e3d33b7babdc79472bd42680aa616f9fc5f2d8 -r6583579862c8623515c9861dd8edec09b6d1898f
--- lams_build/conf/whiteboard/readme.txt (.../readme.txt) (revision 67e3d33b7babdc79472bd42680aa616f9fc5f2d8)
+++ lams_build/conf/whiteboard/readme.txt (.../readme.txt) (revision 6583579862c8623515c9861dd8edec09b6d1898f)
@@ -11,4 +11,6 @@
3.1 In main.js we allow cloning content from another Whiteboard canvas even if target canvas is not empty.
There is also some processing of source data - all images are put in background, so target canvas' drawings go on top.
- 3.2 In server.js we set up default port to 9003 instead of 8080, so it does not collide with WildFly development mode.
\ No newline at end of file
+ 3.2 In server.js we set up default port to 9003 instead of 8080, so it does not collide with WildFly development mode.
+
+ 3.3 In server-backend.js we introduce hashing of wid + accesstoken to improve security
\ No newline at end of file
Index: lams_build/conf/whiteboard/scripts/server-backend.js
===================================================================
diff -u
--- lams_build/conf/whiteboard/scripts/server-backend.js (revision 0)
+++ lams_build/conf/whiteboard/scripts/server-backend.js (revision 6583579862c8623515c9861dd8edec09b6d1898f)
@@ -0,0 +1,403 @@
+const path = require("path");
+
+const config = require("./config/config");
+const ReadOnlyBackendService = require("./services/ReadOnlyBackendService");
+const WhiteboardInfoBackendService = require("./services/WhiteboardInfoBackendService");
+
+function startBackendServer(port) {
+ var fs = require("fs-extra");
+ var express = require("express");
+ var formidable = require("formidable"); //form upload processing
+
+ const createDOMPurify = require("dompurify"); //Prevent xss
+ const { JSDOM } = require("jsdom");
+ const window = new JSDOM("").window;
+ const DOMPurify = createDOMPurify(window);
+
+ const { createClient } = require("webdav");
+
+ var s_whiteboard = require("./s_whiteboard.js");
+
+ var app = express();
+ app.use(express.static(path.join(__dirname, "..", "dist")));
+ app.use("/uploads", express.static(path.join(__dirname, "..", "public", "uploads")));
+ var server = require("http").Server(app);
+ server.listen(port);
+ var io = require("socket.io")(server, { path: "/ws-api" });
+ WhiteboardInfoBackendService.start(io);
+
+ console.log("Webserver & socketserver running on port:" + port);
+
+ const { accessToken, enableWebdav } = config.backend;
+
+ // LAMS introduced this function to enforce security
+ // it mimics WhiteboardService#getWhiteboardAccessTokenHash()
+ const hashAccessToken = function (wid){
+ if (!wid) {
+ return null;
+ }
+ const plainText = wid + accessToken;
+ let hash = 0;
+ for (var i = 0; i < plainText.length; i++){
+ hash = Math.imul(31, hash) + plainText.charCodeAt(i) | 0;
+ }
+ return "" + hash;
+ }
+
+ /**
+ * @api {get} /api/loadwhiteboard Get Whiteboard Data
+ * @apiDescription This returns all the Available Data ever drawn to this Whiteboard
+ * @apiName loadwhiteboard
+ * @apiGroup WhiteboardAPI
+ *
+ * @apiParam {Number} wid WhiteboardId you find in the Whiteboard URL
+ * @apiParam {Number} [at] Accesstoken (Only if activated for this server)
+ *
+ * @apiSuccess {String} body returns the data as JSON String
+ * @apiError {Number} 401 Unauthorized
+ *
+ * @apiExample {curl} Example usage:
+ * curl -i http://[rootUrl]/api/loadwhiteboard?wid=[MyWhiteboardId]
+ */
+ app.get("/api/loadwhiteboard", function (req, res) {
+ const wid = req["query"]["wid"];
+ const at = req["query"]["at"]; //accesstoken
+ const targetWid = req["query"]["targetWid"];
+
+ // if targetWid is present, hash generation is based on combined wids
+ if (accessToken === "" || hashAccessToken(wid + (targetWid || "")) == at) {
+ const widForData = ReadOnlyBackendService.isReadOnly(wid)
+ ? ReadOnlyBackendService.getIdFromReadOnlyId(wid)
+ : wid;
+ const ret = s_whiteboard.loadStoredData(widForData);
+ res.send(ret);
+ res.end();
+ } else {
+ res.status(401); //Unauthorized
+ res.end();
+ }
+ });
+
+ /**
+ * @api {get} /api/getReadOnlyWid Get the readOnlyWhiteboardId
+ * @apiDescription This returns the readOnlyWhiteboardId for a given WhiteboardId
+ * @apiName getReadOnlyWid
+ * @apiGroup WhiteboardAPI
+ *
+ * @apiParam {Number} wid WhiteboardId you find in the Whiteboard URL
+ * @apiParam {Number} [at] Accesstoken (Only if activated for this server)
+ *
+ * @apiSuccess {String} body returns the readOnlyWhiteboardId as text
+ * @apiError {Number} 401 Unauthorized
+ *
+ * @apiExample {curl} Example usage:
+ * curl -i http://[rootUrl]/api/getReadOnlyWid?wid=[MyWhiteboardId]
+ */
+ app.get("/api/getReadOnlyWid", function (req, res) {
+ const wid = req["query"]["wid"];
+ const at = req["query"]["at"]; //accesstoken
+ if (accessToken === "" || hashAccessToken(wid) == at) {
+ res.send(ReadOnlyBackendService.getReadOnlyId(wid));
+ res.end();
+ } else {
+ res.status(401); //Unauthorized
+ res.end();
+ }
+ });
+
+ /**
+ * @api {post} /api/upload Upload Images
+ * @apiDescription Upload Image to the server. Note that you need to add the image to the board after upload by calling "drawToWhiteboard" with addImgBG set as tool
+ * @apiName upload
+ * @apiGroup WhiteboardAPI
+ *
+ * @apiParam {Number} wid WhiteboardId you find in the Whiteboard URL
+ * @apiParam {Number} [at] Accesstoken (Only if activated for this server)
+ * @apiParam {Number} current timestamp
+ * @apiParam {Boolean} webdavaccess set true to upload to webdav (Optional; Only if activated for this server)
+ * @apiParam {String} imagedata The imagedata base64 encoded
+ *
+ * @apiSuccess {String} body returns "done"
+ * @apiError {Number} 401 Unauthorized
+ */
+ app.post("/api/upload", function (req, res) {
+ //File upload
+ var form = new formidable.IncomingForm(); //Receive form
+ var formData = {
+ files: {},
+ fields: {},
+ };
+
+ form.on("file", function (name, file) {
+ formData["files"][file.name] = file;
+ });
+
+ form.on("field", function (name, value) {
+ formData["fields"][name] = value;
+ });
+
+ form.on("error", function (err) {
+ console.log("File uplaod Error!");
+ });
+
+ form.on("end", function () {
+ if (accessToken === "" || hashAccessToken(formData["fields"]["wid"]) == formData["fields"]["at"]) {
+ progressUploadFormData(formData, function (err) {
+ if (err) {
+ if (err == "403") {
+ res.status(403);
+ } else {
+ res.status(500);
+ }
+ res.end();
+ } else {
+ res.send("done");
+ }
+ });
+ } else {
+ res.status(401); //Unauthorized
+ res.end();
+ }
+ //End file upload
+ });
+ form.parse(req);
+ });
+
+ /**
+ * @api {get} /api/drawToWhiteboard Draw on the Whiteboard
+ * @apiDescription Function draw on whiteboard with different tools and more...
+ * @apiName drawToWhiteboard
+ * @apiGroup WhiteboardAPI
+ *
+ * @apiParam {Number} wid WhiteboardId you find in the Whiteboard URL
+ * @apiParam {Number} [at] Accesstoken (Only if activated for this server)
+ * @apiParam {String} t The tool you want to use: "line",
+ * "pen",
+ * "rect",
+ * "circle",
+ * "eraser",
+ * "addImgBG",
+ * "recSelect",
+ * "eraseRec",
+ * "addTextBox",
+ * "setTextboxText",
+ * "removeTextbox",
+ * "setTextboxPosition",
+ * "setTextboxFontSize",
+ * "setTextboxFontColor",
+ * @apiParam {String} [username] The username performing this action. Only relevant for the undo/redo function
+ * @apiParam {Number} [draw] Only has a function if t is set to "addImgBG". Set 1 to draw on canvas; 0 to draw into background
+ * @apiParam {String} [url] Only has a function if t is set to "addImgBG", then it has to be set to: [rootUrl]/uploads/[ReadOnlyWid]/[ReadOnlyWid]_[date].png
+ * @apiParam {String} [c] Color: Only used if color is needed (pen, rect, circle, addTextBox ... )
+ * @apiParam {String} [th] Thickness: Only used if Thickness is needed (pen, rect ... )
+ * @apiParam {Number[]} d has different function on every tool you use:
+ * pen: [width, height, left, top, rotation]
+ *
+ * @apiSuccess {String} body returns the "done" as text
+ * @apiError {Number} 401 Unauthorized
+ */
+ app.get("/api/drawToWhiteboard", function (req, res) {
+ let query = escapeAllContentStrings(req["query"]);
+ const wid = query["wid"];
+ const at = query["at"]; //accesstoken
+ if (!wid || ReadOnlyBackendService.isReadOnly(wid)) {
+ res.status(401); //Unauthorized
+ res.end();
+ }
+
+ if (accessToken === "" || hashAccessToken(wid) == at) {
+ const broadcastTo = (wid) => io.compress(false).to(wid).emit("drawToWhiteboard", query);
+ // broadcast to current whiteboard
+ broadcastTo(wid);
+ // broadcast the same query to the associated read-only whiteboard
+ const readOnlyId = ReadOnlyBackendService.getReadOnlyId(wid);
+ broadcastTo(readOnlyId);
+ s_whiteboard.handleEventsAndData(query); //save whiteboardchanges on the server
+ res.send("done");
+ } else {
+ res.status(401); //Unauthorized
+ res.end();
+ }
+ });
+
+ function progressUploadFormData(formData, callback) {
+ console.log("Progress new Form Data");
+ const fields = escapeAllContentStrings(formData.fields);
+ const wid = fields["whiteboardId"];
+ if (ReadOnlyBackendService.isReadOnly(wid)) return;
+
+ const readOnlyWid = ReadOnlyBackendService.getReadOnlyId(wid);
+
+ const date = fields["date"] || +new Date();
+ const filename = `${readOnlyWid}_${date}.png`;
+ let webdavaccess = fields["webdavaccess"] || false;
+ try {
+ webdavaccess = JSON.parse(webdavaccess);
+ } catch (e) {
+ webdavaccess = false;
+ }
+
+ const savingDir = path.join("./public/uploads", readOnlyWid);
+ fs.ensureDir(savingDir, function (err) {
+ if (err) {
+ console.log("Could not create upload folder!", err);
+ return;
+ }
+ let imagedata = fields["imagedata"];
+ if (imagedata && imagedata != "") {
+ //Save from base64 data
+ imagedata = imagedata
+ .replace(/^data:image\/png;base64,/, "")
+ .replace(/^data:image\/jpeg;base64,/, "");
+ console.log(filename, "uploaded");
+ const savingPath = path.join(savingDir, filename);
+ fs.writeFile(savingPath, imagedata, "base64", function (err) {
+ if (err) {
+ console.log("error", err);
+ callback(err);
+ } else {
+ if (webdavaccess) {
+ //Save image to webdav
+ if (enableWebdav) {
+ saveImageToWebdav(
+ savingPath,
+ filename,
+ webdavaccess,
+ function (err) {
+ if (err) {
+ console.log("error", err);
+ callback(err);
+ } else {
+ callback();
+ }
+ }
+ );
+ } else {
+ callback("Webdav is not enabled on the server!");
+ }
+ } else {
+ callback();
+ }
+ }
+ });
+ } else {
+ callback("no imagedata!");
+ console.log("No image Data found for this upload!", filename);
+ }
+ });
+ }
+
+ function saveImageToWebdav(imagepath, filename, webdavaccess, callback) {
+ if (webdavaccess) {
+ const webdavserver = webdavaccess["webdavserver"] || "";
+ const webdavpath = webdavaccess["webdavpath"] || "/";
+ const webdavusername = webdavaccess["webdavusername"] || "";
+ const webdavpassword = webdavaccess["webdavpassword"] || "";
+
+ const client = createClient(webdavserver, {
+ username: webdavusername,
+ password: webdavpassword,
+ });
+ client
+ .getDirectoryContents(webdavpath)
+ .then((items) => {
+ const cloudpath = webdavpath + "" + filename;
+ console.log("webdav saving to:", cloudpath);
+ fs.createReadStream(imagepath).pipe(client.createWriteStream(cloudpath));
+ callback();
+ })
+ .catch((error) => {
+ callback("403");
+ console.log("Could not connect to webdav!");
+ });
+ } else {
+ callback("Error: no access data!");
+ }
+ }
+
+ io.on("connection", function (socket) {
+ let whiteboardId = null;
+ socket.on("disconnect", function () {
+ WhiteboardInfoBackendService.leave(socket.id, whiteboardId);
+ socket.compress(false).broadcast.to(whiteboardId).emit("refreshUserBadges", null); //Removes old user Badges
+ });
+
+ socket.on("drawToWhiteboard", function (content) {
+ if (!whiteboardId || ReadOnlyBackendService.isReadOnly(whiteboardId)) return;
+
+ content = escapeAllContentStrings(content);
+ if (accessToken === "" || hashAccessToken(content["wid"]) == content["at"]) {
+ const broadcastTo = (wid) =>
+ socket.compress(false).broadcast.to(wid).emit("drawToWhiteboard", content);
+ // broadcast to current whiteboard
+ broadcastTo(whiteboardId);
+ // broadcast the same content to the associated read-only whiteboard
+ const readOnlyId = ReadOnlyBackendService.getReadOnlyId(whiteboardId);
+ broadcastTo(readOnlyId);
+ s_whiteboard.handleEventsAndData(content); //save whiteboardchanges on the server
+ } else {
+ socket.emit("wrongAccessToken", true);
+ }
+ });
+
+ socket.on("joinWhiteboard", function (content) {
+ content = escapeAllContentStrings(content);
+ if (accessToken === "" || hashAccessToken(content["wid"]) == content["at"]) {
+ whiteboardId = content["wid"];
+
+ socket.emit("whiteboardConfig", {
+ common: config.frontend,
+ whiteboardSpecific: {
+ correspondingReadOnlyWid: ReadOnlyBackendService.getReadOnlyId(
+ whiteboardId
+ ),
+ isReadOnly: ReadOnlyBackendService.isReadOnly(whiteboardId),
+ },
+ });
+
+ socket.join(whiteboardId); //Joins room name=wid
+ const screenResolution = content["windowWidthHeight"];
+ WhiteboardInfoBackendService.join(socket.id, whiteboardId, screenResolution);
+ } else {
+ socket.emit("wrongAccessToken", true);
+ }
+ });
+
+ socket.on("updateScreenResolution", function (content) {
+ content = escapeAllContentStrings(content);
+ if (accessToken === "" || hashAccessToken(content["wid"]) == content["at"]) {
+ const screenResolution = content["windowWidthHeight"];
+ WhiteboardInfoBackendService.setScreenResolution(
+ socket.id,
+ whiteboardId,
+ screenResolution
+ );
+ }
+ });
+ });
+
+ //Prevent cross site scripting (xss)
+ function escapeAllContentStrings(content, cnt) {
+ if (!cnt) cnt = 0;
+
+ if (typeof content === "string") {
+ return DOMPurify.sanitize(content);
+ }
+ for (var i in content) {
+ if (typeof content[i] === "string") {
+ content[i] = DOMPurify.sanitize(content[i]);
+ }
+ if (typeof content[i] === "object" && cnt < 10) {
+ content[i] = escapeAllContentStrings(content[i], ++cnt);
+ }
+ }
+ return content;
+ }
+
+ process.on("unhandledRejection", (error) => {
+ // Will print "unhandledRejection err is not defined"
+ console.log("unhandledRejection", error.message);
+ });
+}
+
+module.exports = startBackendServer;
Index: lams_build/conf/whiteboard/src/js/main.js
===================================================================
diff -u -r709049f023d1033d4ef6ec198b08c4e2f94e421a -r6583579862c8623515c9861dd8edec09b6d1898f
--- lams_build/conf/whiteboard/src/js/main.js (.../main.js) (revision 709049f023d1033d4ef6ec198b08c4e2f94e421a)
+++ lams_build/conf/whiteboard/src/js/main.js (.../main.js) (revision 6583579862c8623515c9861dd8edec09b6d1898f)
@@ -37,6 +37,7 @@
const myUsername = urlParams.get("username") || "unknown" + (Math.random() + "").substring(2, 6);
const accessToken = urlParams.get("accesstoken") || "";
const copyfromwid = urlParams.get("copyfromwid") || "";
+const copyaccesstoken = urlParams.get("copyaccesstoken") || "";
// Custom Html Title
const title = urlParams.get("title");
@@ -176,7 +177,10 @@
// Copy from witheboard if current is empty and get parameter is given
$.get(subdir + "/api/loadwhiteboard", {
wid: copyfromwid,
- at: accessToken,
+ // needed for checking hash
+ targetWid: whiteboardId,
+ // this is not the main access token, but a special one just for this operation
+ at: copyaccesstoken,
}).done(function (originalData) {
console.log(originalData);
console.log(data);
Index: lams_tool_whiteboard/src/java/org/lamsfoundation/lams/tool/whiteboard/model/Whiteboard.java
===================================================================
diff -u -rb5f4a44b664ee18ed97ef77d512c6480eb500826 -r6583579862c8623515c9861dd8edec09b6d1898f
--- lams_tool_whiteboard/src/java/org/lamsfoundation/lams/tool/whiteboard/model/Whiteboard.java (.../Whiteboard.java) (revision b5f4a44b664ee18ed97ef77d512c6480eb500826)
+++ lams_tool_whiteboard/src/java/org/lamsfoundation/lams/tool/whiteboard/model/Whiteboard.java (.../Whiteboard.java) (revision 6583579862c8623515c9861dd8edec09b6d1898f)
@@ -134,8 +134,6 @@
Whiteboard toContent = new Whiteboard();
toContent = (Whiteboard) defaultContent.clone();
toContent.setContentId(contentId);
- // copy whiteboard canvas on next open
- toContent.setSourceWid(defaultContent.getContentId().toString());
return toContent;
}
Index: lams_tool_whiteboard/src/java/org/lamsfoundation/lams/tool/whiteboard/service/IWhiteboardService.java
===================================================================
diff -u -rb5f4a44b664ee18ed97ef77d512c6480eb500826 -r6583579862c8623515c9861dd8edec09b6d1898f
--- lams_tool_whiteboard/src/java/org/lamsfoundation/lams/tool/whiteboard/service/IWhiteboardService.java (.../IWhiteboardService.java) (revision b5f4a44b664ee18ed97ef77d512c6480eb500826)
+++ lams_tool_whiteboard/src/java/org/lamsfoundation/lams/tool/whiteboard/service/IWhiteboardService.java (.../IWhiteboardService.java) (revision 6583579862c8623515c9861dd8edec09b6d1898f)
@@ -132,4 +132,6 @@
void saveOrUpdateWhiteboardConfigItem(WhiteboardConfigItem item);
String getWhiteboardServerUrl() throws WhiteboardApplicationException;
+
+ String getWhiteboardAccessTokenHash(String wid, String sourceWid);
}
\ No newline at end of file
Index: lams_tool_whiteboard/src/java/org/lamsfoundation/lams/tool/whiteboard/service/WhiteboardService.java
===================================================================
diff -u -rb5f4a44b664ee18ed97ef77d512c6480eb500826 -r6583579862c8623515c9861dd8edec09b6d1898f
--- lams_tool_whiteboard/src/java/org/lamsfoundation/lams/tool/whiteboard/service/WhiteboardService.java (.../WhiteboardService.java) (revision b5f4a44b664ee18ed97ef77d512c6480eb500826)
+++ lams_tool_whiteboard/src/java/org/lamsfoundation/lams/tool/whiteboard/service/WhiteboardService.java (.../WhiteboardService.java) (revision 6583579862c8623515c9861dd8edec09b6d1898f)
@@ -464,6 +464,22 @@
return whiteboardServerUrl;
}
+ @Override
+ public String getWhiteboardAccessTokenHash(String wid, String sourceWid) {
+ if (StringUtils.isBlank(wid)) {
+ return null;
+ }
+ WhiteboardConfigItem whiteboardAccessTokenConfigItem = getConfigItem(WhiteboardConfigItem.KEY_ACCESS_TOKEN);
+ if (whiteboardAccessTokenConfigItem == null
+ || StringUtils.isBlank(whiteboardAccessTokenConfigItem.getConfigValue())) {
+ return null;
+ }
+ // sourceWid is present when we want to copy content from other canvas
+ String plainText = (StringUtils.isBlank(sourceWid) ? "" : sourceWid) + wid
+ + whiteboardAccessTokenConfigItem.getConfigValue();
+ return String.valueOf(plainText.hashCode());
+ }
+
public static String getWhiteboardAuthorName(UserDTO user) throws UnsupportedEncodingException {
if (user == null) {
return null;
@@ -610,6 +626,8 @@
}
Whiteboard toContent = Whiteboard.newInstance(whiteboard, toContentId);
+ // copy whiteboard canvas on next open
+ toContent.setSourceWid(whiteboard.getContentId().toString());
whiteboardDao.insert(toContent);
if (toContent.isGalleryWalkEnabled() && !toContent.isGalleryWalkReadOnly()) {
Index: lams_tool_whiteboard/src/java/org/lamsfoundation/lams/tool/whiteboard/web/controller/AuthoringController.java
===================================================================
diff -u -rb5f4a44b664ee18ed97ef77d512c6480eb500826 -r6583579862c8623515c9861dd8edec09b6d1898f
--- lams_tool_whiteboard/src/java/org/lamsfoundation/lams/tool/whiteboard/web/controller/AuthoringController.java (.../AuthoringController.java) (revision b5f4a44b664ee18ed97ef77d512c6480eb500826)
+++ lams_tool_whiteboard/src/java/org/lamsfoundation/lams/tool/whiteboard/web/controller/AuthoringController.java (.../AuthoringController.java) (revision 6583579862c8623515c9861dd8edec09b6d1898f)
@@ -36,7 +36,6 @@
import org.lamsfoundation.lams.tool.ToolAccessMode;
import org.lamsfoundation.lams.tool.whiteboard.WhiteboardConstants;
import org.lamsfoundation.lams.tool.whiteboard.model.Whiteboard;
-import org.lamsfoundation.lams.tool.whiteboard.model.WhiteboardConfigItem;
import org.lamsfoundation.lams.tool.whiteboard.model.WhiteboardUser;
import org.lamsfoundation.lams.tool.whiteboard.service.IWhiteboardService;
import org.lamsfoundation.lams.tool.whiteboard.service.WhiteboardApplicationException;
@@ -166,11 +165,14 @@
String whiteboardServerUrl = whiteboardService.getWhiteboardServerUrl();
request.setAttribute("whiteboardServerUrl", whiteboardServerUrl);
- WhiteboardConfigItem whiteboardAccessTokenConfigItem = whiteboardService
- .getConfigItem(WhiteboardConfigItem.KEY_ACCESS_TOKEN);
- if (whiteboardAccessTokenConfigItem != null
- && StringUtils.isNotBlank(whiteboardAccessTokenConfigItem.getConfigValue())) {
- request.setAttribute("whiteboardAccessToken", whiteboardAccessTokenConfigItem.getConfigValue());
+ String wid = authoringForm.getWhiteboard().getContentId().toString();
+ String whiteboardAccessTokenHash = whiteboardService.getWhiteboardAccessTokenHash(wid, null);
+ request.setAttribute("whiteboardAccessToken", whiteboardAccessTokenHash);
+
+ if (StringUtils.isNotBlank(authoringForm.getWhiteboard().getSourceWid())) {
+ String whiteboardCopyAccessTokenHash = whiteboardService.getWhiteboardAccessTokenHash(wid,
+ authoringForm.getWhiteboard().getSourceWid());
+ request.setAttribute("whiteboardCopyAccessToken", whiteboardCopyAccessTokenHash);
}
return "pages/authoring/authoring";
@@ -207,17 +209,17 @@
// get back UID
whiteboardPO.setUid(uid);
- // if whiteboard canvas was copied from another Learning Design,
- // not it becomes the source, i.e. does not copy from anything anymore
- whiteboardPO.setSourceWid(null);
-
// if it's a teacher - change define later status
if (mode.isTeacher()) {
whiteboardPO.setDefineLater(false);
}
whiteboardPO.setUpdated(new Timestamp(new Date().getTime()));
}
+ // if whiteboard canvas was copied from another Learning Design,
+ // not it becomes the source, i.e. does not copy from anything anymore
+ whiteboardPO.setSourceWid(null);
+
// *******************************Handle user*******************
// try to get form system session
HttpSession ss = SessionManager.getSession();
Index: lams_tool_whiteboard/src/java/org/lamsfoundation/lams/tool/whiteboard/web/controller/LearningController.java
===================================================================
diff -u -rb5f4a44b664ee18ed97ef77d512c6480eb500826 -r6583579862c8623515c9861dd8edec09b6d1898f
--- lams_tool_whiteboard/src/java/org/lamsfoundation/lams/tool/whiteboard/web/controller/LearningController.java (.../LearningController.java) (revision b5f4a44b664ee18ed97ef77d512c6480eb500826)
+++ lams_tool_whiteboard/src/java/org/lamsfoundation/lams/tool/whiteboard/web/controller/LearningController.java (.../LearningController.java) (revision 6583579862c8623515c9861dd8edec09b6d1898f)
@@ -35,6 +35,7 @@
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
+import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.lamsfoundation.lams.notebook.model.NotebookEntry;
import org.lamsfoundation.lams.notebook.service.CoreNotebookConstants;
@@ -215,9 +216,19 @@
String whiteboardServerUrl = whiteboardService.getWhiteboardServerUrl();
request.setAttribute("whiteboardServerUrl", whiteboardServerUrl);
- String authorName = WhiteboardService.getWhiteboardAuthorName(currentUserDto);
- request.setAttribute("whiteboardAuthorName", authorName);
+ String whiteboardAuthorName = WhiteboardService.getWhiteboardAuthorName(currentUserDto);
+ request.setAttribute("whiteboardAuthorName", whiteboardAuthorName);
+ String wid = whiteboard.getContentId() + "-" + toolSessionId;
+ String whiteboardAccessTokenHash = whiteboardService.getWhiteboardAccessTokenHash(wid, null);
+ request.setAttribute("whiteboardAccessToken", whiteboardAccessTokenHash);
+
+ if (StringUtils.isNotBlank(whiteboard.getSourceWid())) {
+ String whiteboardCopyAccessTokenHash = whiteboardService.getWhiteboardAccessTokenHash(wid,
+ whiteboard.getSourceWid());
+ request.setAttribute("whiteboardCopyAccessToken", whiteboardCopyAccessTokenHash);
+ }
+
return "pages/learning/learning";
}
Index: lams_tool_whiteboard/web/pages/authoring/basic.jsp
===================================================================
diff -u -rb5f4a44b664ee18ed97ef77d512c6480eb500826 -r6583579862c8623515c9861dd8edec09b6d1898f
--- lams_tool_whiteboard/web/pages/authoring/basic.jsp (.../basic.jsp) (revision b5f4a44b664ee18ed97ef77d512c6480eb500826)
+++ lams_tool_whiteboard/web/pages/authoring/basic.jsp (.../basic.jsp) (revision 6583579862c8623515c9861dd8edec09b6d1898f)
@@ -17,5 +17,5 @@
\ No newline at end of file
Index: lams_tool_whiteboard/web/pages/learning/learning.jsp
===================================================================
diff -u -rb5f4a44b664ee18ed97ef77d512c6480eb500826 -r6583579862c8623515c9861dd8edec09b6d1898f
--- lams_tool_whiteboard/web/pages/learning/learning.jsp (.../learning.jsp) (revision b5f4a44b664ee18ed97ef77d512c6480eb500826)
+++ lams_tool_whiteboard/web/pages/learning/learning.jsp (.../learning.jsp) (revision 6583579862c8623515c9861dd8edec09b6d1898f)
@@ -216,7 +216,7 @@