diff --git a/nodes/core/core/20-inject.js b/nodes/core/core/20-inject.js
index b97f11900..f840f0d2f 100644
--- a/nodes/core/core/20-inject.js
+++ b/nodes/core/core/20-inject.js
@@ -79,20 +79,20 @@ module.exports = function(RED) {
delete this.cronjob;
}
}
-
- RED.httpAdmin.post("/inject/:id", function(req,res) {
- var node = RED.nodes.getNode(req.params.id);
- if (node != null) {
- try {
- node.receive();
- res.send(200);
- } catch(err) {
- res.send(500);
- node.error("Inject failed:"+err);
- console.log(err.stack);
- }
- } else {
- res.send(404);
+
+ RED.httpAdmin.post("/inject/:id", RED.auth.needsPermission("inject.write"), function(req,res) {
+ var node = RED.nodes.getNode(req.params.id);
+ if (node != null) {
+ try {
+ node.receive();
+ res.send(200);
+ } catch(err) {
+ res.send(500);
+ node.error("Inject failed:"+err);
+ console.log(err.stack);
}
+ } else {
+ res.send(404);
+ }
});
}
diff --git a/nodes/core/core/58-debug.js b/nodes/core/core/58-debug.js
index b8106e2b0..d89f2dbc0 100644
--- a/nodes/core/core/58-debug.js
+++ b/nodes/core/core/58-debug.js
@@ -119,7 +119,7 @@ module.exports = function(RED) {
});
RED.log.addHandler(DebugNode.logHandler);
- RED.httpAdmin.post("/debug/:id/:state", function(req,res) {
+ RED.httpAdmin.post("/debug/:id/:state", RED.auth.needsPermission("debug.write"), function(req,res) {
var node = RED.nodes.getNode(req.params.id);
var state = req.params.state;
if (node !== null && typeof node !== "undefined" ) {
diff --git a/public/index.html b/public/index.html
index c4b4a2c41..2dfc882c9 100644
--- a/public/index.html
+++ b/public/index.html
@@ -36,7 +36,7 @@
Deploy
-
+
@@ -240,14 +240,6 @@
-
-
-
@@ -257,6 +249,7 @@
+
diff --git a/public/red/comms.js b/public/red/comms.js
index 8f672bb6d..8a8d1e174 100644
--- a/public/red/comms.js
+++ b/public/red/comms.js
@@ -21,10 +21,23 @@ RED.comms = (function() {
var subscriptions = {};
var ws;
+ var pendingAuth = false;
+
function connectWS() {
var path = location.hostname+":"+location.port+document.location.pathname;
path = path+(path.slice(-1) == "/"?"":"/")+"comms";
path = "ws"+(document.location.protocol=="https:"?"s":"")+"://"+path;
+ var auth_tokens = RED.settings.get("auth-tokens");
+ pendingAuth = (auth_tokens!=null);
+
+ function completeConnection() {
+ for (var t in subscriptions) {
+ if (subscriptions.hasOwnProperty(t)) {
+ ws.send(JSON.stringify({subscribe:t}));
+ }
+ }
+ }
+
ws = new WebSocket(path);
ws.onopen = function() {
if (errornotification) {
@@ -33,19 +46,18 @@ RED.comms = (function() {
errornotification = null;
},1000);
}
- var auth_tokens = RED.settings.get("auth-tokens");
- if (auth_tokens) {
+ if (pendingAuth) {
ws.send(JSON.stringify({auth:auth_tokens.access_token}));
- }
- for (var t in subscriptions) {
- if (subscriptions.hasOwnProperty(t)) {
- ws.send(JSON.stringify({subscribe:t}));
- }
+ } else {
+ completeConnection();
}
}
ws.onmessage = function(event) {
var msg = JSON.parse(event.data);
- if (msg.topic) {
+ if (pendingAuth && msg.auth == "ok") {
+ pendingAuth = false;
+ completeConnection();
+ } else if (msg.topic) {
for (var t in subscriptions) {
if (subscriptions.hasOwnProperty(t)) {
var re = new RegExp("^"+t.replace(/([\[\]\?\(\)\\\\$\^\*\.|])/g,"\\$1").replace(/\+/g,"[^/]+").replace(/\/#$/,"(\/.*)?")+"$");
diff --git a/public/red/main.js b/public/red/main.js
index 2dac4f32d..9bda19015 100644
--- a/public/red/main.js
+++ b/public/red/main.js
@@ -311,34 +311,46 @@ var RED = (function() {
});
if (RED.settings.user) {
- $("#header .username").html(RED.settings.user.username);
- $("#header .user").show();
- RED.menu.addItem("btn-sidemenu", null);
- RED.menu.addItem("btn-sidemenu",{
- id:"btn-logout",
- icon:"fa fa-user",
- label:"Logout",
- onselect:function() {
- // TODO: invalidate token
-
- $.ajax({
- url: "auth/revoke",
- type: "POST",
- data: {token:RED.settings.get("auth-tokens").access_token},
- success: function() {
- RED.settings.remove("auth-tokens");
- document.location.reload(true);
- }
- })
-
- }
+ RED.menu.init({id:"btn-usermenu",
+ options: []
});
+ function updateUserMenu() {
+ $("#btn-usermenu-submenu li").remove();
+ if (RED.settings.user.anonymous) {
+ RED.menu.addItem("btn-usermenu",{
+ id:"btn-login",
+ label:"Login",
+ onselect: function() {
+ RED.user.login({cancelable:true},function() {
+ RED.settings.load(function() {
+ RED.notify("Logged in as "+RED.settings.user.username,"success");
+ updateUserMenu();
+ });
+ });
+ }
+ });
+ } else {
+ RED.menu.addItem("btn-usermenu",{
+ id:"btn-username",
+ icon:"fa fa-user",
+ label:""+RED.settings.user.username+""
+ });
+ RED.menu.addItem("btn-usermenu",{
+ id:"btn-logout",
+ label:"Logout",
+ onselect: function() {
+ RED.user.logout();
+ }
+ });
+ }
+
+ }
+ updateUserMenu();
}
$("#main-container").show();
- $("#btn-deploy").show();
- $("#btn-sidemenu").show();
+ $(".header-toolbar").show();
RED.library.init();
RED.palette.init();
@@ -349,92 +361,14 @@ var RED = (function() {
RED.comms.connect();
loadNodeList();
}
-
- function showLogin() {
- var dialog = $("#node-dialog-login");
- dialog.dialog({
- autoOpen: false,
- dialogClass: "ui-dialog-no-close",
- modal: true,
- closeOnEscape: false,
- width: 600,
- resizable: false,
- draggable: false
- });
- $("#node-dialog-login-fields").empty();
- $.ajax({
- dataType: "json",
- url: "auth/login",
- success: function(data) {
- if (data.type == "credentials") {
- for (var i=0;i",{class:"form-row"});
- $('
').appendTo(row);
- $('').appendTo(row);
- row.appendTo("#node-dialog-login-fields");
- }
- $('').appendTo("#node-dialog-login-fields");
- $("#node-dialog-login-submit").button().click(function( event ) {
- $("#node-dialog-login-submit").button("option","disabled",true);
- $("#node-dialog-login-failed").hide();
- $(".login-spinner").show();
-
- var body = {
- client_id: "node-red-admin",
- grant_type: "password",
- scope:"*"
- }
- for (var i=0;i",{id:options.id+"-submenu", class:"dropdown-menu"}).insertAfter(button);
+ //button.click(function(event) {
+ // $("#"+options.id+"-submenu").show();
+ // event.preventDefault();
+ //});
+
+
+ var topMenu = $("",{id:options.id+"-submenu", class:"dropdown-menu pull-right"}).insertAfter(button);
for (var i=0;i'+
+ ''+
+ ''+
+ ''+
+ '
'+
+ '');
+
+ dialog.dialog({
+ autoOpen: false,
+ dialogClass: "ui-dialog-no-close",
+ modal: true,
+ closeOnEscape: false,
+ width: 600,
+ resizable: false,
+ draggable: false
+ });
+
+ $("#node-dialog-login-fields").empty();
+ $.ajax({
+ dataType: "json",
+ url: "auth/login",
+ success: function(data) {
+ if (data.type == "credentials") {
+ var i=0;
+ for (;i",{class:"form-row"});
+ $('
').appendTo(row);
+ $('').appendTo(row);
+ row.appendTo("#node-dialog-login-fields");
+ }
+ $('').appendTo("#node-dialog-login-fields");
+ $("#node-dialog-login-submit").button().click(function( event ) {
+ $("#node-dialog-login-submit").button("option","disabled",true);
+ $("#node-dialog-login-failed").hide();
+ $(".login-spinner").show();
+
+ var body = {
+ client_id: "node-red-admin",
+ grant_type: "password",
+ scope:"*"
+ }
+ for (var i=0;i webSocketKeepAliveTime) {
+ publish("hb",lastSentTime);
+ }
+ }, webSocketKeepAliveTime);
});
-
wsServer.on('error', function(err) {
log.warn("comms server error : "+err.toString());
});
diff --git a/red/red.js b/red/red.js
index c292df4dd..96f5f8351 100644
--- a/red/red.js
+++ b/red/red.js
@@ -23,6 +23,7 @@ var util = require("./util");
var fs = require("fs");
var settings = require("./settings");
var credentials = require("./nodes/credentials");
+var permissions = require("./api/auth/permissions");
var path = require('path');
@@ -50,6 +51,9 @@ var RED = {
comms: comms,
settings:settings,
util: util,
+ auth: {
+ needsPermission: permissions.needsPermission
+ },
version: function () {
var p = require(path.join(process.env.NODE_RED_HOME,"package.json"));
if (fs.existsSync(path.join(process.env.NODE_RED_HOME,".git"))) {
diff --git a/red/settings.js b/red/settings.js
index b597db38d..d74778db7 100644
--- a/red/settings.js
+++ b/red/settings.js
@@ -83,9 +83,6 @@ var persistentSettings = {
userSettings = null;
globalSettings = null;
storage = null;
-
-
-
}
}
diff --git a/test/red/api/auth/permissions_spec.js b/test/red/api/auth/permissions_spec.js
new file mode 100644
index 000000000..e69de29bb