From 0c5fa597e8c8325ec77a1061fae65497cea57f7b Mon Sep 17 00:00:00 2001 From: mntmn Date: Tue, 2 Jun 2020 20:47:58 +0200 Subject: [PATCH] Allow embedding of folders and access to folders to anonymous editors with edit_hash/spaceAuth links (#63) * add subspaces to be listed with edit_hash/spaceAuth authorization * remove dead code from api_helpers.js * add edit_hash authorization for requested space thumbnails * handle /s/:hash links in frontend router * set space_auth via a function, allow passing it to load_space * rename variable in /s/:hash router in backend * hide search, profile, breadcrumb in folders if not logged in, construct links to subspaces differently for anonymous editors --- middlewares/api_helpers.js | 24 -------- public/javascripts/backend.js | 8 +-- public/javascripts/spacedeck_routes.js | 15 +++++ public/javascripts/spacedeck_sections.js | 7 ++- public/javascripts/spacedeck_spaces.js | 10 +++- routes/api/spaces.js | 76 ++++++++++++++---------- routes/root.js | 12 ++-- views/partials/folders.html | 30 +++++----- 8 files changed, 99 insertions(+), 83 deletions(-) diff --git a/middlewares/api_helpers.js b/middlewares/api_helpers.js index 893f35f..551c7c8 100644 --- a/middlewares/api_helpers.js +++ b/middlewares/api_helpers.js @@ -4,27 +4,6 @@ require('../models/db'); var config = require('config'); const redis = require('../helpers/redis'); -// FIXME TODO object.toJSON() - -var saveAction = (actionKey, object) => { - if (object.constructor.modelName == "Space") - return; - - let attr = { - action: actionKey, - space: object.space_id || object.space, - user: object.user_id || object.user, - editor_name: object.editor_name, - object: object - }; - - /*let action = new Action(attr); - action.save(function(err) { - if (err) - console.error("saved create action err:", err); - });*/ -}; - module.exports = (req, res, next) => { res.header("Cache-Control", "no-cache"); @@ -36,21 +15,18 @@ module.exports = (req, res, next) => { if (!object) return; redis.sendMessage("create", model, object, req.channelId); this.status(201).json(object); - saveAction("create", object); }; res['distributeUpdate'] = function(model, object) { if (!object) return; redis.sendMessage("update", model, object, req.channelId); this.status(200).json(object); - saveAction("update", object); }; res['distributeDelete'] = function(model, object) { if (!object) return; redis.sendMessage("delete", model, object, req.channelId); this.sendStatus(204); - saveAction("delete", object); }; next(); diff --git a/public/javascripts/backend.js b/public/javascripts/backend.js index b57acae..552f3e6 100644 --- a/public/javascripts/backend.js +++ b/public/javascripts/backend.js @@ -6,6 +6,10 @@ var websocket = null; var channel_id = null; var space_auth = null; +function set_space_auth(hash) { + space_auth = hash; +} + function load_resource(method, path, data, on_success, on_error, on_progress) { var req = new XMLHttpRequest(); req.onload = function(evt,b,c) { @@ -44,18 +48,14 @@ function load_resource(method, path, data, on_success, on_error, on_progress) { } req.withCredentials = true; - req.open(method, api_endpoint+"/api"+path, true); if (api_token) { req.setRequestHeader("X-Spacedeck-Auth", api_token); } - if (space_auth) { - console.log("set space auth", space_auth); req.setRequestHeader("X-Spacedeck-Space-Auth", space_auth); } - if (channel_id) { req.setRequestHeader("X-Spacedeck-Channel", channel_id); } diff --git a/public/javascripts/spacedeck_routes.js b/public/javascripts/spacedeck_routes.js index 9d9b382..8e4fd4a 100644 --- a/public/javascripts/spacedeck_routes.js +++ b/public/javascripts/spacedeck_routes.js @@ -17,6 +17,21 @@ var SpacedeckRoutes = { }.bind(this) } ]); + + this.router.add([ + { + path: "/s/:hash", + handler: function(params, on_success) { + var parts = params.hash.split("-"); + if (path.length > 0) { + this.load_space(parts.slice(1).join("-"), on_success, null, parts[0]); + } else { + // FIXME error handling + on_success(); + } + }.bind(this) + } + ]); this.router.add([ { diff --git a/public/javascripts/spacedeck_sections.js b/public/javascripts/spacedeck_sections.js index 7a9fb70..df5daa8 100644 --- a/public/javascripts/spacedeck_sections.js +++ b/public/javascripts/spacedeck_sections.js @@ -405,7 +405,12 @@ var SpacedeckSections = { } if (space.space_type == "folder") return ""; - return "background-image:url('/api/spaces/"+space._id+"/png')"; + var query_string = ""; + if (space_auth) { + query_string+="?spaceAuth="+space.edit_hash; + } + + return "background-image:url('/api/spaces/"+space._id+"/png"+query_string+"')"; }, reset_artifact_filters: function() { diff --git a/public/javascripts/spacedeck_spaces.js b/public/javascripts/spacedeck_spaces.js index aee3217..f802efa 100644 --- a/public/javascripts/spacedeck_spaces.js +++ b/public/javascripts/spacedeck_spaces.js @@ -99,12 +99,16 @@ var SpacedeckSpaces = { }.bind(this), {value: dft || "Guest "+parseInt(10000*Math.random()), ok: __("ok"), cancel: __("cancel")}); }, - load_space: function(space_id, on_success, on_error) { + load_space: function(space_id, on_success, on_error, space_auth) { this.folder_spaces_filter=""; this.folder_spaces_search=""; - space_auth = get_query_param("spaceAuth"); - + if (space_auth) { + set_space_auth(space_auth); + } else { + set_space_auth(get_query_param("spaceAuth")); + } + this.embedded = !!(get_query_param("embedded")); var userReady = function() { diff --git a/routes/api/spaces.js b/routes/api/spaces.js index a74c22d..a8b3a38 100644 --- a/routes/api/spaces.js +++ b/routes/api/spaces.js @@ -42,7 +42,52 @@ var spaceMapping = { thumbnail_url: 1 }; +function listSpacesInFolder(req, res, parent_space_id) { + db.Space + .findOne({where: { + _id: parent_space_id + }}) + .then(function(space) { + if (space) { + function spacesForRole(role) { + if (role == "none") { + if (space.access_mode == "public") { + role = "viewer"; + } + } + if (role != "none") { + db.Space + .findAll({where:{ + parent_space_id: parent_space_id + }, include:[db.CreatorSafeInclude(db)]}) + .then(function(spaces) { + res.status(200).json(spaces); + }); + } else { + res.status(403).json({"error": "not authorized"}); + } + } + + if (req["spaceAuth"] && space.edit_hash) { + // TODO could be editor, too + spacesForRole("none"); + } else { + db.getUserRoleInSpace(space, req.user, spacesForRole); + } + } else { + res.status(404).json({"error": "space not found"}); + } + }); +} + router.get('/', function(req, res, next) { + + if (req.query.parent_space_id && req["spaceAuth"]) { + // list subspaces of a space authorized anonymously + listSpacesInFolder(req, res, req.query.parent_space_id); + return; + } + if (!req.user) { res.status(403).json({ error: "auth required" @@ -83,36 +128,7 @@ router.get('/', function(req, res, next) { } else if (req.query.parent_space_id && req.query.parent_space_id != req.user.home_folder_id) { // list spaces in a folder - db.Space - .findOne({where: { - _id: req.query.parent_space_id - }}) - .then(function(space) { - if (space) { - db.getUserRoleInSpace(space, req.user, function(role) { - if (role == "none") { - if (space.access_mode == "public") { - role = "viewer"; - } - } - - if (role != "none") { - db.Space - .findAll({where:{ - parent_space_id: req.query.parent_space_id - }, include:[db.CreatorSafeInclude(db)]}) - .then(function(spaces) { - res.status(200).json(spaces); - }); - } else { - res.status(403).json({"error": "no authorized"}); - } - }); - } else { - res.status(404).json({"error": "space not found"}); - } - }); - + listSpacesInFolder(req, res, req.query.parent_space_id); } else { // list home folder and spaces/folders that the user is a member of diff --git a/routes/root.js b/routes/root.js index 4c6deb4..1f736c2 100644 --- a/routes/root.js +++ b/routes/root.js @@ -115,16 +115,16 @@ router.get('/t/:id', (req, res) => { res.redirect(path); }); -router.get('/s/:token', (req, res) => { - var token = req.params.token; - if (token.split("-").length > 0) { - token = token.split("-")[0]; +router.get('/s/:hash', (req, res) => { + var hash = req.params.hash; + if (hash.split("-").length > 0) { + hash = hash.split("-")[0]; } - db.Space.findOne({where: {"edit_hash": token}}).then(function (space) { + db.Space.findOne({where: {"edit_hash": hash}}).then(function (space) { if (space) { if (req.accepts('text/html')){ - res.redirect("/spaces/"+space._id + "?spaceAuth=" + token); + res.redirect("/spaces/"+space._id + "?spaceAuth=" + hash); } else { res.status(200).json(space); } diff --git a/views/partials/folders.html b/views/partials/folders.html index 329a91a..e911aff 100644 --- a/views/partials/folders.html +++ b/views/partials/folders.html @@ -8,7 +8,7 @@ [[ __('create_folder') ]] -