Send data on configuration - javascript

I want to send asynchronous data to the node on configuration. I want to
perform a SQL request to list some data in a .
On node creation, a server side function is performed
When it's done, a callback send data to the node configuration
On node configuration, when data is received, the list is created
Alternatively, the binary can request database each x minutes and create a
cache that each node will use on creation, this will remove the asynchronous
part of code, even if it's no longer "live updated".
In fact, i'm stuck because i created the query and added it as below :
module.exports = function(RED) {
"use strict";
var db = require("../bin/database")(RED);
function testNode(n) {
// Create a RED node
RED.nodes.createNode(this,n);
// Store local copies of the node configuration (as defined in the
.html
var node = this;
var context = this.context();
this.on('input', function (msg) {
node.send({payload: true});
});
}
RED.nodes.registerType("SQLTEST",testNode);
}
But I don't know how to pass data to the configuration node. I thought of
Socket.IO to do it, but, is this a good idea and is it available? Do you know any solution ?

The standard model used in Node-RED is for the node to register its own admin http endpoint that can be used to query the information it needs. You can see this in action with the Serial node.
The Serial node edit dialog lists the currently connected serial devices for you to pick from.
The node registers the admin endpoint here: https://github.com/node-red/node-red-nodes/blob/83ea35d0ddd70803d97ccf488d675d6837beeceb/io/serialport/25-serial.js#L283
RED.httpAdmin.get("/serialports", RED.auth.needsPermission('serial.read'), function(req,res) {
serialp.list(function (err, ports) {
res.json(ports);
});
});
Key points:
pick a url that is namespaced to your node type - this avoids clashes
the needsPermission middleware is there to ensure only authenticated users can access the endpoint. The permission should be of the form <node-type>.read.
Its edit dialog then queries that endpoint from here: https://github.com/node-red/node-red-nodes/blob/83ea35d0ddd70803d97ccf488d675d6837beeceb/io/serialport/25-serial.html#L240
$.getJSON('serialports',function(data) {
//... does stuff with data
});
Key points:
here the url must not begin with a /. That ensures the request is made relative to wherever the editor is being served from - you cannot assume it is being served from /.

Related

NGINX JavaScript module with a session storage (like Redis)

I know there is a possibility to process each request via a JS script right inside the NGINX server.
I know there is the Lua Nginx module and the Lua Redis driver, and it's possible to write a script in Lua and use Redis right from the NGINX server.
However, I want to use standard functionality of NGINX and I prefer to code in JS. I wonder is it possible to use some session storage with the NJS? And how to do it? Particularly, I would like to use Redis as a session storage.
If one avoids to compile and install third-party modules for Nginx himself, I suppose the best way to build session storage with njs and Redis is to utilize the builtin ngx_http_upstream_module module and set up something like that
http {
[...]
upstream redis {
server unix:/var/run/redis/nginx.sock;
}
[...]
js_path conf.d/js/;
js_import redismiddleware.js;
[...]
server {
[...]
location /redisadapter {
internal;
try_files #dummy #redis;
}
location /request-we-are-tracking-no-1/ {
js_content redismiddleware.processRequestConditional;
}
[...]
location /request-we-are-tracking-no-2/ {
js_content redismiddleware.processRequestUnconditional;
}
[...]
}
and the corresponding script
var queryString = require('querystring')
function processRequestConditional (request) {
request.subrequest('/redisadapter', {
method : 'POST',
body : queryString.stringify({
/* data to transfer to Redis */
})
}).then(function (response) {
var reply = {}
/**
* parsing and checking feedback from Redis,
* saving some data from feedback to reply
* object, doing any things as planned,
* running any additional routines et
* cetera
*/
if (/* Redis reply is OK */) {
return reply;
} else {
throw new Error('Because we don`t like you!')
}
}).then(function (data) {
/**
* Making one more subrequest to obtain the content
* the client is waiting for
*/
request.subrequest('/secret-url-with-content').then(
(response) => request.return(response.httpStatus, response.body)
)
}).catch((error) {
/**
* Returning to client with response "There will be
* be no response"
*/
request.return(403, error.message)
})
}
function processRequestUnconditional (request) {
request.subrequest('/redisadapter', {
method : 'POST',
body : queryString.stringify({
/* data to transfer to Redis */
})
}).then(function (response) {
/**
* parsing and checking feedback from Redis,
* doing some things, running some or other
* additional routines depending on reply
*/
})
request.subrequest('/secret-url-with-content').then(
(response) => request.return(response.httpStatus, response.body)
)
}
export default { processRequestConditional, processRequestUnconditional }
Short summary
Redis is listening and replying on socket
/var/run/redis/nginx.sock
Virtual internal location /redisadapter receives the requests from njs script, transfers them to Redis and returns the replies back to njs method, which started the requests sequense
To establish data exchange with Redis on some location, we take control over Nginx standard flow and maintain these locations with custom njs methods
Thus, the code in methods in addition to Redis related information exchange routines should itself implement the complete subroutine of retrieving the requested content and delivering this content back to client, since we took this job from Nginx
This is achieved by sets of local subrequests from server to server, which are transparent for clients. njs method completes the set and itself delivers the requested content back to the client
The above example contains two methods, processRequestConditional and processRequestUnconditional, with the goal to show the most used alternative logic ways to maintain such kind of tasks
The first one, processRequestConditional, demonstrates subrequests chain - i.e., the content, requested by client, won't be obtained, until njs method is busy with its primary task transferring the next piece of data into Redis session storage. Moreover, if the script is not satisfied with Redis feedback, the request of content for client is skipped at all, and the client faces refusal message instead
The second method, processRequestUnconditional, transfers the data to Redis storage the same way as the first one above, but this time the fate of the client's request does not depend on results of Redis feedback, thus the secondary request for content is issued at the same time with primary, and flows in parallel while script continue the information exchange round with session storage
Of course, my brief explanation leaves a lot of details behind the scenes, but I hope the basic concept is now clear
Feel free to ask additional questions

Parse Server Node.js SDK: Alternative to Parse.User.become?

I want to completely dissociate my client app from Parse server, to ease the switch to other Baas/custom backend in the future. As such, all client request will point to a node.js server who will make the request to Parse on behalf of the user.
Client <--> Node.js Server <--> Parse Server
As such, I need the node.js server to be able to switch between users so I can keep the context of their authentification.
I know how to authentificate, then keep the sessionToken of the user, and I ve seen during my research than the "accepted" solution to this problem was to call Parse.User.disableUnsafeCurrentUser, then using Parse.User.become() to switch the current user to the one making a request.
But that feels hackish, and I m pretty sure it will, sooner or later, lead to a race condition where the current user is switched before the request is made to Parse.
Another solution I found was to not care about Parse.User, and use the masterKey to save everything by the server, but that would make the server responsible of the ACL.
Is there a way to make request from different user other than thoses two?
Any request to the backend (query.find(), object.save(), etc) takes an optional options parameter as the final argument. This lets you specify extra permissions levels, such as forcing the master key or using a specific session token.
If you have the session token, your server code can make a request on behalf of that user, preserving ACL permissions.
Let's assume you have a table of Item objects, where we rely on ACLs to ensure that a user can only retrieve his own Items. The following code would use an explicit session token and only return the Items the user can see:
// fetch items visible to the user associate with `token`
fetchItems(token) {
new Parse.Query('Item')
.find({ sessionToken: token })
.then((results) => {
// do something with the items
});
}
become() was really designed for the Parse Cloud Code environment, where each request lives in a sandbox, and you can rely on a global current user for each request. It doesn't really make sense in a Node.js app, and we'll probably deprecate it.
I recently wrote a NodeJS application and had the same problem. I found that the combination of Parse.User.disableUnsafeCurrentUser and Parse.User.become() was not only hackish, but also caused several other problems I wasn't able to anticipate.
So here's what I did: I used
Parse.Cloud.useMasterKey(); and then loaded the current user by session ID as if it was a regular user object. It looked something like this:
module.exports = function(req, res, next) {
var Parse = req.app.locals.parse, query;
res.locals.parse = Parse;
if (req.session.userid === undefined) {
res.locals.user = undefined;
return next();
}
Parse.Cloud.useMasterKey();
query = new Parse.Query(Parse.User);
query.equalTo("objectId", req.session.userid);
query.first().then(function(result) {
res.locals.user = result;
return next();
}, function(err) {
res.locals.user = undefined;
console.error("error recovering user " + req.session.userid);
return next();
});
};
This code can obviously be optimized, but you can see the general idea. Upside: It works! Downside: No more use of Parse.User.current(), and the need to take special care in the backend that no conditions occur where someone overwrites data without permission.

meteor - does having publication rules in lib folder present a security risk?

I am following a meteor tutorial on eventedmind. We put the todos collection information in lib/collections/todos.js. The app was generated with iron.
When I load the app in the browser I can plainly see the folder under sources. It looks like:
Todos = new Mongo.Collection('todos');
// if server define security rules
// server code and code inside methods are not affected by allow and deny
// these rules only apply when insert, update, and remove are called from untrusted client code
if (Meteor.isServer) {
// first argument is id of logged in user. (null if not logged in)
Todos.allow({
// can do anythin if you own the document
insert: function (userId, doc) {
return userId === doc.userId;
},
update: function (userId, doc, fieldNames, modifier) {
return userId === doc.userId;
},
remove: function (userId, doc) {
return userId === doc.userId;
}
});
// The deny method lets you selectively override your allow rules
// every deny callback must return false for the database change to happen
Todos.deny({
insert: function (userId, doc) {
return false;
},
update: function (userId, doc, fieldNames, modifier) {
return false;
},
remove: function (userId, doc) {
return false;
}
});
}
My question is does this propose a security threat? If a javascript file is stored in the lib directory can it be hijacked by the client?
Never ever ever ever use Meteor.isServer. Instead put your server methods under /server. Code there is not served up to the client.
I disagree with redress that moving inserts to the server is more secure than doing inserts on the client. After all, a logged-in user can simply open the console and type Meteor.call('addPost', new_post_fields) (after having inspected a document in postsCollection to reverse engineer the schema) and the server will happily execute that. The cost of doing the insert via a method call is that you lose latency compensation, one of the major benefits of Meteor. Your application will feel laggy because your inserts all require a server round-trip to reflect in the UI.
Let me be more specific in response to redress' comments:
If your method code is in /lib it will be visible to both the client and the server and will run once in each place, with latency compensation. It can be modified on the client but not on the server. But it can be seen.
If your method code is in /server it will only be visible to the server and will run without latency compensation.
Meteor.call() can be invoked from the console in the client with any arguments. Your method code needs to protect against such attacks.
I recommend using a combination of allow/deny rules on the server along with aldeed:simple-schema at a minimum to control what goes into your collections.

Using NodeJS with Express 3.x and Jade templates is it possible to just re-render one item for a previously rendered list?

I have been trying to find any post that can explain if it is possible to re-render one 'new' item (append) to a jade template list.
Say that we have a list of log-entries and upon first request we render a fetched list from a MongoDB collection 'logs', using res.render and Jades each functionality.
Since we like to retrieve updates from the database we also have a MongoWatch attached to that collection that listens for changes. Upon update can we execute some code that appends to that first list in the Jade-template?
/* app.js */
/*
Display server log
*/
app.get ('/logs', function(req, res, next) {
// Using Monk to retrieve data from mongo
var collection = db.get('logs');
collection.find({}, function(e,docs){
// watch the collection
watcher.watch('application.logs', function(event){
// Code that update the logs list with the new single entry event.data?
});
// Request resources to render
res.render('logs', { logs: docs } );
});
});
<!-- logs.jade -->
extends layout
block content
div
each log in logs
div.entry
p.url= log.url
Maybe i should use the template engine in another fashion, i am quite new to Express, Jade and really appreciate all you guys that spends your time answering problems like these..
// Regards
Ok, so i have looked up the suggestion from Jonathan Lenowski, thanks by the way!, and i came up with a solution to my problem. Thought i'd follow up and perhaps help someone else along the way..
Basically i am now using as suggested socket.io
So first install the socket.io npm module by adding it to package.json and run npm install, i used 'latest' as version.
Next to use the 'socket.io.js' on the client-side you actually have to copy the file from the installed socket.io module to your javascript folder.
Path (seen from project root is): 'node_modules/socket.io/node_modules/socket.io-client/dist/'
Setup DB, Watcher, Webserver, Socket and controller on server-side
/*
SETUP DATABASE HANDLE
in app.js
*/
var mongo = require('mongodb');
var monk = require('monk');
var db = monk('localhost:'+app.get('port')+'/application');
/* SETUP DATABASE UPDATE WATCH */
var watcher = new MongoWatch({ format: 'pretty', host: 'localhost', port: app.get('port') });
/* START WEBSERVER AND SETUP WEBSOCKET */
var server = Https.createServer({key: certData.serviceKey, cert: certData.certificate}, app);
var io = require('socket.io').listen(server);
server.listen(app.get('port'), function(){
console.log('Express server listening on port ' + app.get('port'));
});
/*
Display server log - controller
*/
app.get ('/logs', function(req, res, next) {
// Using Monk to retrieve data from mongo
var collection = db.get('logs');
collection.find({}, function(e,docs){
// watch the collection logs in database application
watcher.watch('application.logs', function(event){
io.sockets.emit('logs', { log: event.data });
});
// Request resources to render
res.render('logs', { logs: docs } );
});
});
Include the socket.io javascript in layout
/*
Add client side script
in layout.jade
*/
script(type='text/javascript' src='/javascripts/socket.io.js')
Use the client
/*
SETUP DATABASE HANDLE
in logs.jade
*/
extends layout
block content
script.
var socket = io.connect('https://localhost:4431');
socket.on('logs', function (data) {
console.log(data.log);
// Here we use javascript to add a .log-entry to the list
// This minor detail i leave to the developers own choice of tools
});
div.row#logs
div.col-sm-12
div.header-log Some application
div.logs-section
each log in logs
div.log-entry.col-sm-12(data-hook=log.status)
p.method= log.method
p.url= log.url
p.status(style='color: #'+log.color+' !important')= log.status
p.response-time= log.time
p.content-length= log.length
p.datetime= log.date
Use the functionality, remember that this flow is triggered by actually adding a row in the database 'application' and the collection 'logs'.
I use ssl thus with regular http we create a 'http' server instead and connect from the client with a standard address prefix of http://...
Also as an additional note, in order to use MongoWatch it is required of you to setup the MongoDB with replication set. Which is a mirror database that can be used as a fallback (dual purpose).
Cheers! And once again thanks to Jonathan!

Sending client side form input to server side database query via Node.js and return results to client

I am developing a web application where the user can type in a "device id" on the web page (we have 100's of devices out on the field in production use each with a unique ID), that result entered by the user will be sent to the Node.js server that in return will store it into a variable and use it in a SQL Query to retrieve results about that particular device from the database server and then display the results back to the client web page.
Currently the form input feature has not been implemented yet even though I've already coded the form code in html.
The program works fine as it is if I were to manually change the DEVICE_ID to the device I wish to retrieve data from in the code but of course I want to be able to enter this on the client page instead of me having to change it in the server-side source code manually.
"use strict";
var pg = require('pg').native;
var http = require('http');
var $ = require('cheerio');
var fs = require('fs');
var url = require('url');
var htmlString = fs.readFileSync('index.html').toString();
var parsedHTML = $.load(htmlString);
var dbUrl = "tcp://URL HERE/";
// The Sign-ID
var DEVICE_ID = '2001202';
// Create the http server
http.createServer(function (request, response) {
var request = url.parse(request.url, true);
var action = request.pathname;
// Connect and query the database
pg.connect(dbUrl, function(err, client) {
// The complete sql query for everything that's needed for the app!
client.query("SQL QUERY IS HERE" + DEVICE_ID + "etc..",
function (err, result) {
// Remaining program code is here that performs DOM based
// manipulation to display results returned from the server
// to the client side page.
// Time to Render the document and output to the console
console.log(parsedHTML.html());
// Render the document and project onto browser
response.end(parsedHTML.html());
}
); // End client.query
}); // End pg.connect
}).listen(8080); // End http.CreateServer
pg.end();
I've considered the following:
1) Use An OnClick() function from within the HTML code, like this:
onclick="lookupSignID()
Then include an external JS file from within the HTML that includes the lookupSignID() function however I soon found out this is only performing client-side function and is not what I want.
2) AJAX is only good for if the server is generating new information by itself, therefore I can't use AJAX since the user is entering the device ID to get information from it.
3) Possibly using POST/ GET
Can anyone please advise on what course of action I should take? If solution (3) is the best way how would I go about doing this? Can it be integrated into my existed code (shown above) without many changes?
Thanks!
If you used jQuery on the client side with an AJAX POST function, and then on the server side, you have express.js, you could do this:
app.post('/deviceid', function(req, res) {
var deviceid = req.param('deviceid')
console.log(deviceid)
...
})

Categories

Resources