Skip to content

Commit

Permalink
Merge pull request #1 from Doom4535/5-creating-user-from-flow
Browse files Browse the repository at this point in the history
5 creating user from flow
  • Loading branch information
Doom4535 authored May 7, 2019
2 parents 60a8a10 + 4663210 commit 308815b
Show file tree
Hide file tree
Showing 5 changed files with 313 additions and 26 deletions.
10 changes: 10 additions & 0 deletions nodes/locales/en-US/users_manager.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"users": {
"errors": {
"user-management-required": "msg.user_management is a required property",
"user-management-action-required": "msg.user_management.action is a required property",
"user-management-username-required": "msg.user_management.username is a required property",
"user-management-password-required": "msg.user_management.password is a required property"
}
}
}
62 changes: 62 additions & 0 deletions nodes/users_manager.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<script type="text/javascript">
RED.nodes.registerType('users_manager',{
category: 'function',
color: '#00abb0',
defaults: {
name: {value:""}
},
inputs:1,
outputs:1,
paletteLabel: "User Cred Manager",
icon: "users.png",
label: function() {
return this.name||"User Credential Manager";
}
});
</script>

<script type="text/x-red" data-template-name="users_manager">
<div class="form-row">
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="User Credentials Manager">
</div>
</script>

<script type="text/x-red" data-description-name="users_manager">
<h1>Credential Manager</h1>
<p>This node is currently in develeopement, see help section for links to project.</p>
<p>This node is used to allow the creation, update, and deletion of user accounts from within the flow</p>
</script>

<script type="text/x-red" data-help-name="users_manager">
<h1>Credential Manager</h1>
<p>This node is used to manage the node-red-contrib-users credentials</p>
<p>This node is currently in developement and does not work</p>
<p><a href="https://github.com/SenseTecnic/node-red-contrib-users#node-red-contrib-users" target="_blank">Original Project Link</a></p>
<p><a href="https://github.com/Doom4535/node-red-contrib-users#node-red-contrib-users" target"_blank">Current developement Branch</a></p>

<h3>Input</h3>
<dl class="message-properties">
<dt>
Message Input
<span class="property-type">object</span>
</dt>
<dd> The input object is named 'user_management' and is located in the message root, such that it is received as 'msg.user_management'.</dd>
<dd>The input object consists of three property: 'action', 'username', and 'password'.</dd>
<dd>The 'action' can take 4 different string input options: 'create', 'update', 'update_or_create', and 'delete'.</dd>
<dd>The 'username' property takes in a string for the username to operate against.</dd>
<dd>The 'password' property takes in a string for the password to set or update, this field has no effect on a 'delete' action call.</dd>
</dl>

<h3>Output</h3>
<dl class="message-properties">
<dt>
Message Output
<span class="property-type">object</span>
</dt>
<dd>The output object consists of the original input object, with the added 'result' and 'error' properties.</dd>
<dd>The 'result' property contains any messages that are generated upon success.</dd>
<dd>The 'error' property contains a string error message of any encountered error messages.</dd>
</dl>
</script>

140 changes: 140 additions & 0 deletions nodes/users_manager.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
var path = require('path');
var users = require('../users');


function checkedRequiredFields(RED, node, config, msg) {
// Message testing conditions
/*
if !(msg.hasOwnProperty('user_management')){
throw new Error("users.errors.user-management-required");
}
if !(msg.user_management.hasOwnProperty('action')){
throw new Error("users.errors.user-management-action-required");
}
if !(msg.user_management.hasOwnProperty('username')){
throw new Error("users.errors.user-management-username-required");
}
if !(msg.user_management.hasOwnProperty('password')){
throw new Error("users.errors.user-management-password-required");
}
*/
}

module.exports = function (RED) {

function UsersManagerNode(n) {
RED.nodes.createNode(this,n);
var node = this;
node.status({});

// Searching though all nodes to find the users_config node
// to extract the credentials from
var config;
RED.nodes.eachNode(function (n) {
if (n.type === "users_config") {
config = n;
config.credentials = RED.nodes.getCredentials(n.id);
}
});

node.on('input', function (msg) {
try {
checkedRequiredFields(RED, node, config, msg);
} catch (err) {
node.error(RED._(err.message));
node.status({fill: "red", shape: "ring", text: RED._(err.message)});
msg.res.status(500);
msg.res.send("Error: invalid config");
}
user_m = msg.user_management;
switch(user_m.action) {
case 'test':
user_m.result = users.getUser('operator','operator');
break;
case 'find':
var result = users.getUserAccount(user_m.username);
if(result == null){
user_m.result = "Null User";
}
else {
user_m.result = users.getUserAccount(user_m.username);
}
break;
case 'create':
if(users.getUserExistance(user_m.username)){
// We have encountered an issue
user_m.error = "Creation request error, user alredy exists";
}
else {
user_m.result = "Creation request";
users.addUser(user_m.username, user_m.password);
var success = users.getUserExistance(user_m.username);
if (success) {
user_m.result = "Created the new user";
}
else {
user_m.error = "Failed to create the new user";
}
}
break;
case 'update':
if(users.getUserExistance(user_m.username) != null){
// This does not verify write permissions
users.updateUser(user_m.username, user_m.username, user_m.password);
// Update the user
user_m.result = "Updated user";
}
else{
// We have encountered an error
user_m.error = "Update request error, user does not exist";
}
break;
case 'update_or_create':
// Create the user (we can be indiscriminate b/c
// we want to overwrite the old record if it exists
if(users.getUserExistance(user_m.username) == null){
// User doesn't exist, create
users.addUser(user_m.username, user_m.password);
user_m.result = "Created user";
}
else {
// User exists, we will delete them and then recreate
// This does not verify the password (does not check if user has permission to change)
users.updateUser(user_m.username, user_m.username, user_m.password);
user_m.result = "Updated user";
}
break;
case 'delete':
if(users.getUser(user_m.username, user_m.password) != null){
// This does not verify the password (does not check if user has permission to change)
users.deleteUser(user_m.username);
// Delete the user
user_m.result = "Deleted user";
}
else{
// We have encountered an error
user_m.error = "Delete request error";
}
break;
default:
// Default action
user_m.error = "Default action triggered";
}

if (user_m.hasOwnProperty('error')) {
node.status({fill: "yellow", shape: "dot", text: "Invalid"});
//node.send([msg, null]);
} else {
node.status({fill: "green", shape: "dot", text: "Valid"});
}

// Testing function
msg.user_management = user_m;
credentials = config.credentials;
msg.payload = credentials;
node.send(msg);
});
}

RED.nodes.registerType("users_manager", UsersManagerNode);
};
70 changes: 48 additions & 22 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,37 +1,63 @@
{
"name": "node-red-contrib-users",
"version": "0.1.7",
"description": "A node used to quickly build a simple user system to control access to your http nodes on Node-RED.",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
"_from": "node-red-contrib-users",
"_id": "[email protected]",
"_inBundle": false,
"_integrity": "sha512-u/kRkO7X3YsPcPBefyJenJ6cAD5gJhr00IXo9Gnzcbc7DooRYpXcESQQZ4gNF3PLxHXzdmP+2rOALLxIl9JDog==",
"_location": "/node-red-contrib-users",
"_phantomChildren": {},
"_requested": {
"type": "tag",
"registry": true,
"raw": "node-red-contrib-users",
"name": "node-red-contrib-users",
"escapedName": "node-red-contrib-users",
"rawSpec": "",
"saveSpec": null,
"fetchSpec": "latest"
},
"repository": {
"type": "git",
"url": "git+https://github.com/SenseTecnic/node-red-contrib-users.git"
"_requiredBy": [
"#USER"
],
"_resolved": "https://registry.npmjs.org/node-red-contrib-users/-/node-red-contrib-users-0.1.7.tgz",
"_shasum": "1c9a2188565ae89b0d6f4074dda69401f50532ee",
"_spec": "node-red-contrib-users",
"_where": "/home/aaron",
"bugs": {
"url": "https://github.com/SenseTecnic/node-red-contrib-users/issues"
},
"bundleDependencies": false,
"contributors": [
{
"name": "Ted Huang"
}
],
"dependencies": {
"bcrypt": "^2.0.0",
"cookie": "^0.3.1",
"jsonwebtoken": "^8.2.1"
},
"deprecated": false,
"description": "A node used to quickly build a simple user system to control access to your http nodes on Node-RED.",
"homepage": "https://github.com/SenseTecnic/node-red-contrib-users#readme",
"keywords": [
"node-red",
"user management"
],
"license": "",
"name": "node-red-contrib-users",
"node-red": {
"nodes": {
"users_config": "nodes/users_config.js",
"users_manager": "nodes/users_manager.js",
"users_isloggedin": "nodes/users_isloggedin.js"
}
},
"contributors": [
{
"name": "Ted Huang"
}
],
"license": "",
"bugs": {
"url": "https://github.com/SenseTecnic/node-red-contrib-users/issues"
"repository": {
"type": "git",
"url": "git+https://github.com/Doom4535/node-red-contrib-users.git"
},
"homepage": "https://github.com/SenseTecnic/node-red-contrib-users#readme",
"dependencies": {
"bcrypt": "^2.0.0",
"cookie": "^0.3.1",
"jsonwebtoken": "^8.2.1"
}
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"version": "0.1.8"
}
57 changes: 53 additions & 4 deletions users.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,54 @@ function hash(username, password) {
}

function getUser(username, password) {
var user = usersConfig.credentials.nodeUsers.filter(function (u) {
return u.username === username && u.password === hash(username, password);
})[0];
var user = getUserAccount(username);
// Check if the credentials provided match, if they don't return null
return user.password == hash(username, password) ? user : null
}

// Check if there is an account that matches the provided username
function getUserAccount(username) {
var user = usersConfig.credentials.nodeUsers.find(function (u) {
return u.username == username
});
return user;
}

function getUserExistance(username){
existance = (getUserAccount(username) != null) ? true : false;
return existance
}

function addUser(username, password){
usersConfig.credentials.nodeUsers.push({
username: username,
password: hash(username, password),
scope: ''
});
}

function updateUser(original_username, new_username, new_password){
var user = getUserAccount(original_username);
if (user != null){
user.username = new_username;
user.password = hash(original_username, new_password);
deleteUser(original_username);
userConfig.credentials.nodeUsers.push(user);
return getUser(new_username);
}
return user;
}

function deleteUser(username){
// We shouldn't ever let there be more than one occurance of a user, but we don't do
// anything to ensure it. Lets loop through to ensure that there are non leftover
while(getUserExistance(username)){
usersConfig.credentials.nodeUsers.splice(usersConfig.credentials.nodeUsers.findIndex(function (u) {
return(u.username == username);
}),1);
}
}

function handleLogin(req, res) {
if (!usersConfig || !usersConfig.credentials || !usersConfig.credentials.jwtSecret) {
log.error("Node users: missing or incomplete users config");
Expand Down Expand Up @@ -159,5 +201,12 @@ module.exports = {

init(RED.server, RED.httpNode, RED.log, RED.settings);
},
hash: hash,
getUserExistance: getUserExistance,
getUserAccount: getUserAccount,
getUser: getUser,
addUser: addUser,
updateUser, updateUser,
deleteUser: deleteUser,
verify: verifyJwt
};
};

0 comments on commit 308815b

Please sign in to comment.