Get variable from client-side JavaScript file in Express - javascript

I am trying to send a variable from my client-side JavaScript file to my server-side app.js file. I know that you can get a value from something like a form input field using methods such as the one below (using Express):
var express = require('express');
var app = express();
var path = require('path');
let cityResponse;
app.post('/city', function(req,res) {
cityResponse = {
user_name: req.body.userName
}
res.sendFile(path.join(__dirname, '/client/city/index.html'));
});
But I would like to get a value not directly from the HTML, but from the JavaScript file that the HTML is attached to.
As well as this, I am currently using Socket.io to send the data from the server to the client, and vice versa, using a window.onload to let the server know when the page is ready:
index.js
window.onload = function() {
socket.emit('cityPageReady');
console.log("city page ready");
};
socket.on('cityPageInfo', function(cityResponse) {
console.log('city page info received');
console.log(cityResponse);
console.log(cityResponse.user_name);
userName = cityResponse.user_name;
document.getElementById("name").innerHTML = userName;
});
app.js
var city = io.of('/city').on('connection', (socket) => {
console.log('A user has connected!');
socket.on('cityPageReady', function() {
socket.emit('cityPageInfo', cityResponse);
console.log('city page ready recieved');
});
});
This works, but many people have said that this is overkill, or as one person put it, "using a hammer to kill a bee". Ideally, I'd like to use the optimal method. I do know that template engines can achieve this, but I do not want to have to rewrite all my HTML just to be able to send a single variable to the server.
To reiterate, my questions are:
How would I get a variable from the client-side JavaScript file (not the HTML)?
What is the best way to send these variables back over to client-side?
Any help would be greatly appreciated.

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('/');
}
});

Is there some way of importing a variable(specifically map) from the server side onto the client side(Socket.io)?

I am trying to assign unique colors to each different client( by using socket.id ). In my map() I have paired (socket.id,randomcolor()), but this variable is on the server side. I've found out that the require() statement doesn't work on client side,
why is that and what is a solution to it? I want to be able to pass map() variable to the client side so that it uses the color assigned to that socket.id and displays the color accordingly.
Or is there some way to know the socket.id on the client side(I don't think it is but not sure), specifically a users computer has to know who sent the message i.e. what socket.id was used to send the message, Is it possible to know that?
Here's my server side:
var express = require('express');
var app = express();
app.use(express.static('public'))
var http = require('http').createServer(app);
var io = require('socket.io')(http);
const map = new Map();
io.on('connection', function(socket) {
console.log('connected by ' + socket.id);
map.set(socket.id, RandomColor())
socket.on('chat', function(data) {
//emitting to all sockets connected
io.emit('chat', data);
console.log(map.entries());
});
socket.on('typing', function(data) {
socket.broadcast.emit('typing', data);
})
});
http.listen(3000, function() {
console.log('listening on port 3000');
});
Here's client side :
// import '../index';
var socket = io.connect('http://localhost:3000')
var message = document.getElementById('Message');
var handle = document.getElementById('Handle');
var btn = document.getElementById('Send');
var output = document.getElementById('Output');
var feedback = document.getElementById('Feedback');
var ids = []
console.log(server);
//emit event
btn.addEventListener('click', function() {
socket.emit('chat', {
message: message.value,
handle: handle.value,
})
})
message.addEventListener('keypress', function() {
socket.emit('typing', handle.value)
})
messageArray = []
//listening for any message received
socket.on('chat', function(data) {
// console.log(data);
feedback.innerHTML = ""
var item = document.createElement('li')
item.innerHTML = "<span style=\"font-family:\"cursive\";\" ;><strong>" + data.handle + ": " + data.message + "</strong></span>";
document.getElementById('Output').appendChild(item)
})
//listening for any typing event listener
socket.on('typing', function(data) {
feedback.innerHTML = "<p><strong>" + data + " is typing a message </strong></p>";
})
PS: Also, I'm new to JS and Socket.io so please suggest some good practices for anything in the code.
First of all, JS has no built-in include/reference property.
So you can't just join another file into another file. But some libraries achieve this with their own written methods etc.
A JS executed on the client-side is not able to access local files. Although you may access an online file load into the document or to an object. So similar functionality can be achieved via 3rd party scripts.
Node.JS follows the CommonJS module system and uses the power of being able to access the local file system.
About the index: So you don't need a Map and Map is pretty similar to a standard object, main difference is might be the order of contents.
But since all you need is a dictionary object. Just create a simple object. Then you can emit the color index whenever you want.
const colorIndex = {}
colorIndex[socketID] = color
Each can set their color on client-side and send it to the server, on each update server has to update every other client about the color.
A client cannot know other clients otherwise wouldn't be secure and it doesn't work like that. It works more like you are calling someone and the server is a middle man that connecting you two.
So, create an object, store socket ids, nicknames, any other info you need. Keep it on serverside, on each message send all of them together with the message.
const users = {}
io.on('connection', function(socket) {
users[socket.id] = {//Add new user
color:RandomColor()
}
socket.on('chat', function(message) {
let u = users[socket.id];//Get user from index
let data = {//Create a message package
user:(u.username)?u.username:"Guest", //name of the user if set
color:u.color,//color of user
message
}
io.emit('chat', data );//Send
});
socket.on('setColor', function(color) {//User can update color
users[socket.id].color = color
});
socket.on('setname', function(name) {//User can update username
users[socket.id].username = name
});
});
So you probably get the idea. There are bunch of ways to achieve.
I don't think you could send that map as an argument, but you can't try creating an array of arrays and emit it to an event like io.emit(colors, array) and once you have it on the client side you can transform back to a map using something like map or reduce
RequireJS is responsible to handle dependencies and ensure that you have everything you need. It is a Javascript library which can work anywhere you use Javascript at, including your server and client-side. The reason it does not work on your client-side (which manifests in the error you see) is that it's not configured on your client-side.
You can read about configurating RequireJS as well.
However, if you set it up properly on your client-side, then there might still be issues, particularly if you try to use on your client-side something which is available on the server. Client-side is a browser, potentially very far from the server. Luckily there is a client API for Socket.IO.
EDIT
Server and client-side can share values in several ways:
WebSockets (a duplex protocol which should be chosen if available in most cases)
Push notifications
AJAX
Page load
Forever frame (that's a hack which should be avoided)

How can I dynamically assign a database path in Express.js based on login?

I have a backend service that I would like to use as a single point of entry for my web application, and dynamically assign a database path based on the user login.
I realize that this is not a scalable solution. I intend to use it during a testing period with several clients (accessing the ALPHA database), and also setting up a demo (accessing the SAND database).
I have the following module that I have written as a simple test to see if the login is for the demo user, all other logins will go to the other resource:
config.js
var express = require('express');
var app = express();
module.exports.dbPath = function (login){
console.log('login - ', login);
if (login === 'demo#mysite.com'){
return process.env.DB_SAND;
} else {
return process.env.DB_ALPHA;
}
};
My question is, how can I manage each unique login and assign a globally accessible reference for that session to direct each user session consistently to the correct database?
Am I overcomplicating this? If there is a different approach that would be a better practice I would welcome a suggestion in another direction.
I would use it as a middleware, and attach it to the req object for each user, something similar this:
module.exports = {
dbPath: function(req, res, next){
var login = req.body.login;
console.log('login - ', login);
if (login === 'demo#mysite.com'){
req.dbPath = 'DB_SAND';
} else {
req.dbPath = 'DB_ALPHA';
}
next();
}
};

Updating data realtime in Node.js express website

I'm trying to achieve something what I think should be very simple to do, but all the tutorials and examples I find seem to be an overkill.
What I am doing:
I'm fetching weather info periodically, and I want to update the text on the website everytime its fetched without user having to refresh the browser.
Almost every tutorial on realtime data updating recommends using socket.io and I have given it a try, but I can't get it to do what I want and I'm starting to think that there should be an easier way and that socket.io might not be the best way to go about this. Any suggestions? How do I get simple line of text update on website without user having to refresh the page?
My weather script:
var express = require('express');
var app = express();
var server = require('http').Server(app);
var io = require('socket.io')(server);
function refreshWeather() {
var temperature = getTemperature();
io.sockets.emit('broadcast', {
temperature : temperature
});
}
My jade script:
doctype html
html
head
link(rel='stylesheet', href='/css/index.css')
title Dashboard
body
script(src='/socket.io/socket.io.js')
script.
var socket = io();
socket.on('broadcast', function (data) {
// UPDATE WEATHER HERE
});
.main-content
h1 Weather is: // I WANT THIS TO BE UPDATED
You could:
Get rid of socket.io.
Make an end point for retrieving the temperature.
Do some polling on the frontend.
Backend would look something like this:
var express = require('express');
var app = express();
var server = require('http').Server(app);
app.get('/weather', function (req, res) {
res.send(getTemperature())
});
Frontend would look something like this:
doctype html
html
head
link(rel='stylesheet', href='/css/index.css')
title Dashboard
body
.main-content
h1(id='weather') Weather is: // I WANT THIS TO BE UPDATED
script.
setInterval(function () {
fetch('/some/url', {
method: 'get'
}).then(function(response) {
// UPDATE WEATHER HERE
document.getElementById('weather').innerHTML = response
}).catch(function(err) {
// Error :(
});
}, 1000) // milliseconds
Code is totally untested, so please try not to copy and paste — adapt it instead. Also, if you're going to use the fetch API, you might want to use a polyfill, otherwise, just use plain ajax.

"has no method 'getscript'" in Node.js server using Express

I have a server in Node.js and I use Express to make a web app.
My server (app.js) gets data from a form (by Ajax post method) and I want that it proceeds this data by using the code of another file (anotherfile.js).
I used this solution: https://stackoverflow.com/a/950146/3303704 and I included this code in my app.js file:
app.post('/', function(req, res) {
$.getScript("anotherfile.js", function(){
alert("Script loaded and executed.");
});
});
But Node.js returns me that "has no method 'getscript'".
Idea of the cause and solution? Thanks!
You appear to be trying to use jQuery in node.
The solution you have linked to is a solution for front-end.
Use require() in node.
Try reading this article: Node.js, Require and Exports. It explains that for instance if you define this in one file called user.js:
var User = function(name, email) {
this.name = name;
this.email = email;
};
module.exports = User;
You can do this in another:
var user = require('./user');
var u = new user.User();

Categories