Better permission handling in editor

This commit is contained in:
Nick O'Leary 2018-01-12 21:00:11 +00:00
parent bb168d35a8
commit 1204cf1ba0
No known key found for this signature in database
GPG Key ID: 4F2157149161A6C9
10 changed files with 240 additions and 111 deletions

View File

@ -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)) {

View File

@ -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) {

View File

@ -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;

View File

@ -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 = $('<div style="position: relative">').appendTo(pane);
var summaryContent = $('<div></div>',{style:"color: #999"}).appendTo(summary);
updateProjectSummary(activeProject.summary, summaryContent);
$('<button class="editor-button editor-button-small" style="float: right;">edit</button>')
.prependTo(summary)
.click(function(evt) {
evt.preventDefault();
editSummary(activeProject, activeProject.summary, summaryContent);
});
if (RED.user.hasPermission("projects.write")) {
$('<button class="editor-button editor-button-small" style="float: right;">edit</button>')
.prependTo(summary)
.click(function(evt) {
evt.preventDefault();
editSummary(activeProject, activeProject.summary, summaryContent);
});
}
$('<hr>').appendTo(pane);
var description = $('<div class="node-help" style="position: relative"></div>').appendTo(pane);
@ -239,13 +246,14 @@ RED.projects.settings = (function() {
updateProjectDescription(activeProject, descriptionContent);
$('<button class="editor-button editor-button-small" style="float: right;">edit</button>')
.prependTo(description)
.click(function(evt) {
evt.preventDefault();
editDescription(activeProject, descriptionContent);
});
if (RED.user.hasPermission("projects.write")) {
$('<button class="editor-button editor-button-small" style="float: right;">edit</button>')
.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 = $('<div id="project-settings-tab-deps" class="project-settings-tab-pane node-help"></div>');
$('<button class="editor-button editor-button-small" style="margin-top:10px;float: right;">edit</button>')
.appendTo(pane)
.click(function(evt) {
evt.preventDefault();
editDependencies(activeProject,null,pane,depsList)
});
if (RED.user.hasPermission("projects.write")) {
$('<button class="editor-button editor-button-small" style="margin-top:10px;float: right;">edit</button>')
.appendTo(pane)
.click(function(evt) {
evt.preventDefault();
editDependencies(activeProject,null,pane,depsList)
});
}
var depsList = $("<ol>",{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 = $('<button class="editor-button editor-button-small palette-module-button">add to project</button>').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 = $('<button class="editor-button editor-button-small palette-module-button">add to project</button>').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 = $('<button class="editor-button editor-button-small palette-module-button">remove from project</button>').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 = $('<button class="editor-button editor-button-small palette-module-button">remove from project</button>').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 = $('<h3></h3>').text("Files").appendTo(pane);
var filesContainer = $('<div class="user-settings-section"></div>').appendTo(pane);
var editFilesButton = $('<button class="editor-button editor-button-small" style="float: right;">edit</button>')
.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 = $('<button class="editor-button editor-button-small" style="float: right;">edit</button>')
.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

View File

@ -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,

View File

@ -283,7 +283,10 @@ RED.sidebar.versionControl = (function() {
refreshFiles(result);
});
}
})
});
RED.events.on("login",function() {
refresh(true);
});
sidebarContent = $('<div>', {class:"sidebar-version-control"});
var stackContainer = $("<div>",{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();

View File

@ -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;

View File

@ -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;i<permission.length;i++) {
if (!checkPermission(userScope,permission[i])) {
return false;
}
}
// All permissions check out
return true;
}
if (Array.isArray(userScope)) {
if (userScope.length === 0) {
return false;
}
for (i=0;i<userScope.length;i++) {
if (checkPermission(userScope[i],permission)) {
return true;
}
}
return false;
}
if (userScope === "*" || userScope === permission) {
return true;
}
if (userScope === "read" || userScope === "*.read") {
return readRE.test(permission);
} else if (userScope === "write" || userScope === "*.write") {
return writeRE.test(permission);
}
return false;
}
return {
init: init,
login: login,
logout: logout
logout: logout,
hasPermission: hasPermission
}
})();

View File

@ -23,6 +23,10 @@
#project-settings-tab-settings {
overflow-y: scroll;
}
.sidebar-version-control-shade {
background: #f3f3f3;
}
.projects-edit-form form {
margin: 0;
.form-row {

View File

@ -76,7 +76,12 @@
"password": "Password",
"login": "Login",
"loginFailed": "Login failed",
"notAuthorized": "Not authorized"
"notAuthorized": "Not authorized",
"errors": {
"settings": "You must be logged in to access settings",
"deploy": "You must be logged in to deploy changes",
"notAuthorized": "You must be logged in to perform this action"
}
},
"notification": {
"warning": "<strong>Warning</strong>: __message__",