Execute Server Side Code While Node Is Running - javascript

I am building a slack copy cat app for practice and want to implement the ability for users to create their own messaging space. When creating a message space, a unique key is created and stored to my database. My plan is to use these unique keys to serve the same html page that has the messaging functionality. In theory this would work, but I am having trouble retrieving the keys AND using them to route to my message.html file. Is there a way to run my server, retrieve the keys and store them to a global variable THEN route to the html page? I'm using Node, Express and MongoDB.
Here is what my code looks like on the back end to retrieve the keys:
var dbKeys = [];
db.messageSpaces.find({}, {"_id": 0, "name": 0}, function(error, data) {
if (error) {
console.log(error);
}
else {
for (var i = 0; i < data.length; i++) {
dbKeys.push(data[i].key);
}
}
});
And how I am attempted to route them:
for (var i = 0; i < dbKeys.length; i++) {
app.get(`/${dbKeys[i]}`, function(req, res) {
res.sendFile(path.join(__dirname, "public/message.html"));
});
}

I think I would use a single call to app.get and use one of the techniques described in https://expressjs.com/en/guide/routing.html#route-parameters to perform basic validation of the format. Perhaps something like this:
app.get('/:id([a-z0-9]{16})', function(req, res) {
console.log(req.params.id);
});
The above assumes that an id is 16 characters long and consists of lowercase letters and numbers only.
You would then check whether the message space id corresponds to a real message space inside the get handler. If it doesn't you could either handle the error or pass it on down the middleware chain by calling next() (you would need to add next as an argument to your handler for that to work).

Related

Is this a secure enough method to recover data?

I'd love to know if this method I'm using is secure enough to use on a public project, since I can't really find any other way to retrieve my id from my currently logged in user, but it's a fairly straightforward method , I find. If this method is not secure would it be possible to have a way to proceed? Thanks in advance.
I have a button for example when I use the send of the html that there is inside my div userid on the server to then use this information to make SQL queries from my app.js server.
I use socket.io hbs express node js jwt mysql
From my pages.js file generated with the express library where the main roads of my website are located, I send my user ID.
router.get('/accueil', authController.isLoggedIn, (req, res) => {
if(req.user) {
res.render('./accueil', {
data: req.user.id
});
} else {
res.redirect('/');
}
});
With Handlebars I display this data in my index.hbs (display: none;).
<div id="iduser">{{data}}</div>
Then I get my iduser div on my client.js
let userid = document.getElementById('iduser').innerHTML;
// (My method to display this div)
socket.on('uid', (data) => {
pargent.innerHTML = JSON.stringify(data.data[0].argent);
})
//
So I want to use this userid variable to make SQL queries from my app.js.
(let userid = document.getElementById('iduser').innerHTML;)
I am using socket.io for communication between client and server to send my userid data
Example :
db.query('UPDATE users SET money = money + ? WHERE id = ?', [100, theUserId]);
No
Never trust user supplied data.
References:
https://www.oreilly.com/library/view/http-developers-handbook/0672324547/0672324547_ch22lev1sec1.html
https://flylib.com/books/en/1.290.1.90/1/
https://www.garybell.co.uk/never-trust-user-input/
https://medium.com/#berniedurfee/never-trust-a-client-not-even-your-own-2de342723674
https://www.invicti.com/blog/web-security/input-validation-errors-root-of-all-evil/
https://laravel-news.com/never-trust-your-users
https://www.wearenova.co.uk/nova-blog/when-it-comes-to-online-security-why-you-should-never-trust-a-client
It depends on your authController.isLoggedIn logic,
But I would like to suggest an alternative solution simple as that;
iron-session
Read their docs, it's matches your use case and easy to use; here is equivalent of the snippet you provided with iron session:
//initiate session middleware yourself
router.use(session)
// later here
router.get('/accueil', (req, res) => {
if(req.session.user) {
res.render('./accueil', {
data: req.user.id
});
} else {
res.redirect('/');
}
});

How to declare a static array in Node.js?

I am trying to create a static array named "categories" whom I wish it will be initialized ONCE in my Node.js application. I mean, when I close the app and run it again - I want it to KEEP the state of the "categories" array.
What happens is that the array is initialized for each time I run this app. Though I want it to be declared only once in this app's lifetime.
router.post("/add_category", (req, res, next) => {
var category = req.body.category;
categories.push(category);
res.render("index", { categories });
});
The simplest solution is to just write the array to a file as JSON and then load that back in when your server starts.
let categories = require('./categories.json');
router.post("/add_category", (req, res, next) => {
var category = req.body.category;
categories.push(category);
fs.writeFile(`./categories.json`, JSON.stringify(categories), () => {
res.render("index", { categories });
});
});
Node.js, by itself, does not have any automatically persisted variables that get saved to disk by themselves and are automatically available the next time you run the program. You have to code that yourself.
You should need a database for that kind of data persistence. But at times, a full-blown database (MongoDB, SQL) could be considered overkill since you only need to save a simple array.
So, consider using the "node-persist" package, here's a possible solution:
const storage = require('node-persist');
storage.initSync();
storage.setItem('categories', [ . . . ] );
console.log(storage.getItem('categories'));
That is was databases are for. Consider Using some SQL or noSQL database that will store values even if server is reseted.

Node.js Express app insert app.local.setting only once when logged in

I have a node.js + Express app. I am using Passport for user login. There is a system settings table in my database which I want to read from when a user successfully logs in and then create app.locals.setting_name local variables from it, which will be used during the lifetime of the application.
The settings table has the Name and Value columns which represent the setting name and its corresponding value. So something like: Name - SUPPORT_EMAIL and Value - support#email.com, as an example.
So I would have app.locals.SUPPORT_EMAIL value set as support#email.com
Here is the code I have so far:
app.js
var settingsObj = require('./config/appSettings.js');
app.use(function(req, res, next) {
...
...
settingsObj.getApplicationSystemSetting(req.user, app);
next();
});
appSettings.js
exports.getApplicationSystemSetting = function() {
connectionPool.getConnection(function(err, connection){
connection.query('select Name, Value from SystemSettings', function(err, rows){
if(err) {
winston.log('info', '--------------------- ERROR: ' + err);
return;
}
console.log('-------------- settings: ' + JSON.stringify(rows));
for(var i = 0; i < rows.length; i++) {
var setting = rows[i];
app.locals.setting.Name = setting.Value;
}
});
});
}
There are however two problems I am facing:
1) The app.use calls the settings code every time I go to a new page. I just want this code to be called only once when the user logs in.
2) The app.locals are not set. If I do a debug app.locals.SUPPORT_EMAIL as undefined.
Any suggestions or ideas on how this can improve?
So, two things. app.use will, in fact, happen on every request. The easiest way to deal with your need is to simply have that middleware check for app.user and if it's not there call next() without doing anything else. So the middleware is called but doesn't try to set locals.
Second issue, your function that sets app.locals doesn't actually use the parameters you're passing it (note the function signature in your second code block), and it is async, so there's a good chance that the middleware is calling next() before it's ever executed. Change the function signature to:
function(user, locals, callback)
and then have the middleware pass 'next' as the callback. The locals object you pass should actually be res.locals as you only want to set the variable for that response, not the whole app.

Express API - Verifying req.body elements

Am building an api using express and node.js.
I'm working on basic validation and want to verify items being passed in exist and are safe (done in addition to validation on client side).
So i have teh following:
router.post('/register', function(req, res) {
for (var itemsFromBody in req.body){
console.log(itemsFromBody);
}
However when i check the console all i see are the names of the Keys e.g. username, email etc, not the values themselves.
How do i obtain those?
Also I'll be doing validation on those eg making sure its not empty - do i need to follow a simple if-then statement or is there some nice npm package that exists that allows me to verify?
Thanks!
for (var itemsFromBodyIndex in req.body){
if (req.body.hasOwnProperty(itemsFromBodyIndex)) {
console.log(req.body[itemsFromBodyIndex]);
}
}
This should work !
Useful links:
https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Instructions/for...in
https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Object/hasOwnProperty
And what about an error catcher into the loop if all of your fields are required ?
for (var itemsFromBodyIndex in req.body){
if (req.body.hasOwnProperty(itemsFromBodyIndex)) {
console.log(req.body[itemsFromBodyIndex]);
if(req.body[itemsFromBodyIndex] == null){
// handle empty field
}
}
}
The for -- in will only give you keys, as you noticed above. You need to use those keys to get the values
for (var itemsFromBody in req.body){
console.log("Key: " + itemsFromBody + " Value: " + req.body[itemsFromBody]);
}

What does a Node.js web service look like?

I am taking a look at Node.js and thinking about using it for building an API. From what I can tell, ExpressJS would be the web framework and is not what I'd be looking for to solve this.
So what would a web service look like? Would it simply be creating a server, talking to mongo and returning results? Also, what does routing look like? (I'd obviously want to 'design' the routes).
If Express would be your web framework, look at the express-resource (Github) middleware for routing an API. You define resources and it'll wire up REST-style routing for you with very little boilerplate.
app.resource('horses', require('./routes/horses'), { format: json })
Given the above, express-resource will hook up all the REST-style routes to actions you supply, returning JSON by default. In routes/horses.js, you export actions for that resource, along the lines of:
exports.index = function index (req, res) {
// GET http://yourdomain.com/horses
res.send( MyHorseModel.getAll() )
}
exports.show = function show (req, res) {
// GET http://yourdomain.com/horses/seabiscuit
res.send( MyHorseModel.get(req.params.horse) )
}
exports.create = function create (req, res) {
// PUT http://yourdomain.com/horses
if (app.user.canWrite) {
MyHorseModel.put(req.body, function (ok) { res.send(ok) })
}
}
// ... etc
You can respond with different representations:
exports.show = {
json: function (req, res) {
// GET http://yourdomain/horses/seabiscuit.json
}
, xml: function (req, res) {
// GET http://yourdomain/horses/seabiscuit.xml
}
}
Middlewares like express-resource can make life with Node and Express much easier, take a look through the examples on github to see if it'll do what you need.
Here is a stub that looks up a horse name from a Postgres database and returns the result as JSON. Clients would access would access the API by going to address such as http://yourdomain.com/api/horse/seabiscuit
app.get('/api/horse/:name', function(req, res){
pg.connect(conString, function(err, client) {
var horse = req.params.name;
var sql = "...";
client.query(sql, function(err, result) {
if (err) {
...
}
for (var i=0; i<result.rows.length; i++) {
// Customize data as needed
}
return res.send(JSON.stringify(result.rows));
});
});
});
Node is pretty low level. It's like C in JavaScript's clothing. Since it's comparable to C, there's pretty much a lot you can do with Node. Creating web servers is just one of them. You can create live chat servers using sockets, blogs, streaming etc. The possibilities are infinite. You are limited only by your imagination.
Routing is just a task where you take in commands (commonly via URL or headers) and do tasks based on those commands passed.
But even I have not yet scathed the surface of node. It's API is huge and getting bigger. Better try using some basic library like Express or Connect first since they pretty much abstract the basic requirement of building the server from code.

Categories