From 1204cf1ba0eef8469fc40b161072a20a357bad82 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Fri, 12 Jan 2018 21:00:11 +0000 Subject: [PATCH] Better permission handling in editor --- editor/js/main.js | 68 +++++----- editor/js/settings.js | 36 +++--- editor/js/ui/deploy.js | 4 + editor/js/ui/projects/projectSettings.js | 131 +++++++++++--------- editor/js/ui/projects/projects.js | 29 ++++- editor/js/ui/projects/tab-versionControl.js | 9 +- editor/js/ui/userSettings.js | 4 + editor/js/user.js | 59 ++++++++- editor/sass/projects.scss | 4 + red/api/editor/locales/en-US/editor.json | 7 +- 10 files changed, 240 insertions(+), 111 deletions(-) diff --git a/editor/js/main.js b/editor/js/main.js index 9352cd18d..b6b06b1a8 100644 --- a/editor/js/main.js +++ b/editor/js/main.js @@ -104,42 +104,48 @@ } if (notificationId === "runtime-state") { if (msg.error === "credentials_load_failed") { - options.buttons = [ - { - text: "Setup credentials", - click: function() { - RED.projects.showCredentialsPrompt(); + if (RED.user.hasPermission("projects.write")) { + options.buttons = [ + { + text: "Setup credentials", + click: function() { + RED.projects.showCredentialsPrompt(); + } } - } - ] + ] + } } else if (msg.error === "missing_flow_file") { - options.buttons = [ - { - text: "Setup project files", - click: function() { - persistentNotifications[notificationId].close(); - delete persistentNotifications[notificationId]; - RED.projects.showFilesPrompt(); + if (RED.user.hasPermission("projects.write")) { + options.buttons = [ + { + text: "Setup project files", + click: function() { + persistentNotifications[notificationId].close(); + delete persistentNotifications[notificationId]; + RED.projects.showFilesPrompt(); + } } - } - ] + ] + } } else if (msg.error === "project_empty") { - options.buttons = [ - { - text: "No thanks", - click: function() { - persistentNotifications[notificationId].close(); - delete persistentNotifications[notificationId]; + if (RED.user.hasPermission("projects.write")) { + options.buttons = [ + { + text: "No thanks", + click: function() { + persistentNotifications[notificationId].close(); + delete persistentNotifications[notificationId]; + } + }, { + text: "Create default project files", + click: function() { + persistentNotifications[notificationId].close(); + delete persistentNotifications[notificationId]; + RED.projects.createDefaultFileSet(); + } } - }, { - text: "Create default project files", - click: function() { - persistentNotifications[notificationId].close(); - delete persistentNotifications[notificationId]; - RED.projects.createDefaultFileSet(); - } - } - ] + ] + } } } if (!persistentNotifications.hasOwnProperty(notificationId)) { diff --git a/editor/js/settings.js b/editor/js/settings.js index 19a385166..9594bec43 100644 --- a/editor/js/settings.js +++ b/editor/js/settings.js @@ -63,7 +63,7 @@ RED.settings = (function () { if (!hasLocalStorage()) { return; } - if (key === "auth_tokens") { + if (key === "auth-tokens") { localStorage.removeItem(key); } else { delete userSettings[key]; @@ -161,23 +161,25 @@ RED.settings = (function () { } function saveUserSettings() { - if (pendingSave) { - clearTimeout(pendingSave); + if (RED.user.hasPermission("settings.write")) { + if (pendingSave) { + clearTimeout(pendingSave); + } + pendingSave = setTimeout(function() { + pendingSave = null; + $.ajax({ + method: 'POST', + contentType: 'application/json', + url: 'settings/user', + data: JSON.stringify(userSettings), + success: function (data) { + }, + error: function(jqXHR,textStatus,errorThrown) { + console.log("Unexpected error saving user settings:",jqXHR.status,textStatus); + } + }); + },300); } - pendingSave = setTimeout(function() { - pendingSave = null; - $.ajax({ - method: 'POST', - contentType: 'application/json', - url: 'settings/user', - data: JSON.stringify(userSettings), - success: function (data) { - }, - error: function(jqXHR,textStatus,errorThrown) { - console.log("Unexpected error saving user settings:",jqXHR.status,textStatus); - } - }); - },300); } function theme(property,defaultValue) { diff --git a/editor/js/ui/deploy.js b/editor/js/ui/deploy.js index 956742c56..b967f4db8 100644 --- a/editor/js/ui/deploy.js +++ b/editor/js/ui/deploy.js @@ -286,6 +286,10 @@ RED.deploy = (function() { function save(skipValidation,force) { if (!$("#btn-deploy").hasClass("disabled")) { + if (!RED.user.hasPermission("flows.write")) { + RED.notify(RED._("user.errors.deploy"),"error"); + return; + } if (!skipValidation) { var hasUnknown = false; var hasInvalid = false; diff --git a/editor/js/ui/projects/projectSettings.js b/editor/js/ui/projects/projectSettings.js index a4221205b..5bf4a3d18 100644 --- a/editor/js/ui/projects/projectSettings.js +++ b/editor/js/ui/projects/projectSettings.js @@ -40,6 +40,11 @@ RED.projects.settings = (function() { if (settingsVisible) { return; } + if (!RED.user.hasPermission("projects.write")) { + RED.notify(RED._("user.errors.notAuthorized"),"error"); + return; + } + settingsVisible = true; var tabContainer; @@ -226,12 +231,14 @@ RED.projects.settings = (function() { var summary = $('
').appendTo(pane); var summaryContent = $('
',{style:"color: #999"}).appendTo(summary); updateProjectSummary(activeProject.summary, summaryContent); - $('') - .prependTo(summary) - .click(function(evt) { - evt.preventDefault(); - editSummary(activeProject, activeProject.summary, summaryContent); - }); + if (RED.user.hasPermission("projects.write")) { + $('') + .prependTo(summary) + .click(function(evt) { + evt.preventDefault(); + editSummary(activeProject, activeProject.summary, summaryContent); + }); + } $('
').appendTo(pane); var description = $('
').appendTo(pane); @@ -239,13 +246,14 @@ RED.projects.settings = (function() { updateProjectDescription(activeProject, descriptionContent); - $('') - .prependTo(description) - .click(function(evt) { - evt.preventDefault(); - editDescription(activeProject, descriptionContent); - }); - + if (RED.user.hasPermission("projects.write")) { + $('') + .prependTo(description) + .click(function(evt) { + evt.preventDefault(); + editDescription(activeProject, descriptionContent); + }); + } return pane; } function updateProjectDependencies(activeProject,depsList) { @@ -349,12 +357,14 @@ RED.projects.settings = (function() { function createDependenciesPane(activeProject) { var pane = $('
'); - $('') - .appendTo(pane) - .click(function(evt) { - evt.preventDefault(); - editDependencies(activeProject,null,pane,depsList) - }); + if (RED.user.hasPermission("projects.write")) { + $('') + .appendTo(pane) + .click(function(evt) { + evt.preventDefault(); + editDependencies(activeProject,null,pane,depsList) + }); + } var depsList = $("
    ",{style:"position: absolute;top: 60px;bottom: 20px;left: 20px;right: 20px;"}).appendTo(pane); depsList.editableList({ addButton: false, @@ -368,28 +378,30 @@ RED.projects.settings = (function() { row.parent().addClass("palette-module-section"); } headerRow.text(entry.label); - if (entry.index === 1) { - var addButton = $('').appendTo(headerRow).click(function(evt) { - evt.preventDefault(); - var deps = $.extend(true, {}, activeProject.dependencies); - for (var m in modulesInUse) { - if (modulesInUse.hasOwnProperty(m) && !modulesInUse[m].known) { - deps[m] = modulesInUse[m].version; + if (RED.user.hasPermission("projects.write")) { + if (entry.index === 1) { + var addButton = $('').appendTo(headerRow).click(function(evt) { + evt.preventDefault(); + var deps = $.extend(true, {}, activeProject.dependencies); + for (var m in modulesInUse) { + if (modulesInUse.hasOwnProperty(m) && !modulesInUse[m].known) { + deps[m] = modulesInUse[m].version; + } } - } - editDependencies(activeProject,JSON.stringify(deps,"",4),pane,depsList); - }); - } else if (entry.index === 3) { - var removeButton = $('').appendTo(headerRow).click(function(evt) { - evt.preventDefault(); - var deps = $.extend(true, {}, activeProject.dependencies); - for (var m in activeProject.dependencies) { - if (activeProject.dependencies.hasOwnProperty(m) && !modulesInUse.hasOwnProperty(m)) { - delete deps[m]; + editDependencies(activeProject,JSON.stringify(deps,"",4),pane,depsList); + }); + } else if (entry.index === 3) { + var removeButton = $('').appendTo(headerRow).click(function(evt) { + evt.preventDefault(); + var deps = $.extend(true, {}, activeProject.dependencies); + for (var m in activeProject.dependencies) { + if (activeProject.dependencies.hasOwnProperty(m) && !modulesInUse.hasOwnProperty(m)) { + delete deps[m]; + } } - } - editDependencies(activeProject,JSON.stringify(deps,"",4),pane,depsList); - }); + editDependencies(activeProject,JSON.stringify(deps,"",4),pane,depsList); + }); + } } } else { headerRow.addClass("palette-module-header"); @@ -630,26 +642,27 @@ RED.projects.settings = (function() { function createFilesSection(activeProject,pane) { var title = $('

    ').text("Files").appendTo(pane); var filesContainer = $('').appendTo(pane); - var editFilesButton = $('') - .appendTo(title) - .click(function(evt) { - evt.preventDefault(); - formButtons.show(); - editFilesButton.hide(); - flowFileLabelText.hide(); - flowFileInput.show(); - flowFileInputSearch.show(); - credFileLabel.hide(); - credFileInput.show(); - flowFileInput.focus(); - // credentialStateLabel.parent().hide(); - credentialStateLabel.addClass("uneditable-input"); - $(".user-settings-row-credentials").show(); - credentialStateLabel.css('height','auto'); - credentialFormRows.hide(); - credentialSecretButtons.show(); - }); - + if (RED.user.hasPermission("projects.write")) { + var editFilesButton = $('') + .appendTo(title) + .click(function(evt) { + evt.preventDefault(); + formButtons.show(); + editFilesButton.hide(); + flowFileLabelText.hide(); + flowFileInput.show(); + flowFileInputSearch.show(); + credFileLabel.hide(); + credFileInput.show(); + flowFileInput.focus(); + // credentialStateLabel.parent().hide(); + credentialStateLabel.addClass("uneditable-input"); + $(".user-settings-row-credentials").show(); + credentialStateLabel.css('height','auto'); + credentialFormRows.hide(); + credentialSecretButtons.show(); + }); + } var row; // Flow files diff --git a/editor/js/ui/projects/projects.js b/editor/js/ui/projects/projects.js index a559c798a..ff7981400 100644 --- a/editor/js/ui/projects/projects.js +++ b/editor/js/ui/projects/projects.js @@ -1753,6 +1753,10 @@ RED.projects = (function() { } else if (!activeProject.empty) { throw new Error("Cannot create default file set on a non-empty project"); } + if (!RED.user.hasPermission("projects.write")) { + RED.notify(RED._("user.errors.notAuthorized"),"error"); + return; + } createProjectOptions = {}; show('default-files',{existingProject: true}); // var payload = { @@ -1805,11 +1809,18 @@ RED.projects = (function() { return { init: init, - _show: show, showStartup: function() { + if (!RED.user.hasPermission("projects.write")) { + RED.notify(RED._("user.errors.notAuthorized"),"error"); + return; + } show('welcome'); }, newProject: function() { + if (!RED.user.hasPermission("projects.write")) { + RED.notify(RED._("user.errors.notAuthorized"),"error"); + return; + } if (!activeProject) { show('welcome'); } else { @@ -1817,15 +1828,31 @@ RED.projects = (function() { } }, selectProject: function() { + if (!RED.user.hasPermission("projects.write")) { + RED.notify(RED._("user.errors.notAuthorized"),"error"); + return; + } show('open') }, deleteProject: function() { + if (!RED.user.hasPermission("projects.write")) { + RED.notify(RED._("user.errors.notAuthorized"),"error"); + return; + } show('delete') }, showCredentialsPrompt: function() { //TODO: rename this function + if (!RED.user.hasPermission("projects.write")) { + RED.notify(RED._("user.errors.notAuthorized"),"error"); + return; + } RED.projects.settings.show('settings'); }, showFilesPrompt: function() { //TODO: rename this function + if (!RED.user.hasPermission("projects.write")) { + RED.notify(RED._("user.errors.notAuthorized"),"error"); + return; + } RED.projects.settings.show('settings'); }, createDefaultFileSet: createDefaultFileSet, diff --git a/editor/js/ui/projects/tab-versionControl.js b/editor/js/ui/projects/tab-versionControl.js index 89c577677..62746e723 100644 --- a/editor/js/ui/projects/tab-versionControl.js +++ b/editor/js/ui/projects/tab-versionControl.js @@ -283,7 +283,10 @@ RED.sidebar.versionControl = (function() { refreshFiles(result); }); } - }) + }); + RED.events.on("login",function() { + refresh(true); + }); sidebarContent = $('
    ', {class:"sidebar-version-control"}); var stackContainer = $("
    ",{class:"sidebar-version-control-stack"}).appendTo(sidebarContent); sections = RED.stack.create({ @@ -1175,6 +1178,10 @@ RED.sidebar.versionControl = (function() { stagedChangesList.editableList('empty'); unmergedChangesList.editableList('empty'); } + if (!RED.user.hasPermission("projects.write")) { + return; + } + refreshInProgress = true; refreshLocalCommits(); diff --git a/editor/js/ui/userSettings.js b/editor/js/ui/userSettings.js index 594129f87..59bf085b1 100644 --- a/editor/js/ui/userSettings.js +++ b/editor/js/ui/userSettings.js @@ -29,6 +29,10 @@ RED.userSettings = (function() { if (settingsVisible) { return; } + if (!RED.user.hasPermission("settings.write")) { + RED.notify(RED._("user.errors.settings"),"error"); + return; + } settingsVisible = true; var tabContainer; diff --git a/editor/js/user.js b/editor/js/user.js index 063f4d243..4d004a218 100644 --- a/editor/js/user.js +++ b/editor/js/user.js @@ -188,6 +188,7 @@ RED.user = (function() { RED.settings.load(function() { RED.notify(RED._("user.loggedInAs",{name:RED.settings.user.username}),"success"); updateUserMenu(); + RED.events.emit("login",RED.settings.user.username); }); }); } @@ -230,10 +231,66 @@ RED.user = (function() { } } + + var readRE = /^((.+)\.)?read$/ + var writeRE = /^((.+)\.)?write$/ + + function hasPermission(permission) { + if (permission === "") { + return true; + } + if (!RED.settings.user) { + return true; + } + return checkPermission(RED.settings.user.permissions||"",permission); + } + function checkPermission(userScope,permission) { + if (permission === "") { + return true; + } + var i; + + if (Array.isArray(permission)) { + // Multiple permissions requested - check each one + for (i=0;iWarning: __message__",