JavaScript code substitution on client side - javascript

I'm now learning some new technologies (such as node.js, socket.io, redis etc.) and making some simple test applications to see how it can work.
My question is about security on a client-side javascript code: for example, i have a chat-server on node.js+express and when a user connects to this chat, server should assign his registred username (authorisation through oldschool php+mysql is used) to his socket. The question is, can user modify his client-side script and connect to chat under different users' names?
Some code is given below:
(server-side part of assigning username, which is just getting the username from client-side call)
// when the client emits 'adduser', this listens and executes
socket.on('adduser', function(username){
// store the username in the socket session for this client
socket.username = username;
// store the room name in the socket session for this client
socket.room = 'General';
// add the client's username to the global list
usernames[username] = username;
// send client to room 1
socket.join('General');
// echo to client they've connected
socket.emit('updatechat', 'SERVER', 'you have connected to General');
// echo to room 1 that a person has connected to their room
socket.broadcast.to('General').emit('updatechat', 'SERVER', username + ' has connected to this room');
socket.emit('updaterooms', rooms, 'General');
});
(client-side part of sending username to server, it looks like 'var username = "User";' for a particular user)
Yii::$app->view->registerJs('var username = "'.$user->identity->username.'";', yii\web\View::POS_HEAD);
(connect function)
chat.on('connect', function(){
// call the server-side function 'adduser' and send one parameter (value of prompt)
chat.emit('adduser', username);
});
SO the question is: can user change (for example, through chrome development tools) his username in line 'var username ...' and connect to chat under the different name?
P.S. this particular situation is just an example, obviously, changed nicknames in chat are not more than a simple joke, but similar situations can appear in other projects...

Supposing your variables are protected in closures and that it's not trivial to change them by typing username='root' in the console, a user could simply replace the whole code.
Everything that happens client side is totally out of your control.
The good news is that they are solutions not involving a duplicate authentication. Supposing you already authenticate the user in your express application, you can get the session and the user from that.
See how I do it in my chat server :
var sessionSockets = new SessionSockets(io, sessionStore, cookieParser);
sessionSockets.on('connection', function (err, socket, session) {
function die(err){
console.log('ERR', err);
socket.emit('error', err.toString());
socket.disconnect();
}
if (! (session && session.passport && session.passport.user && session.room)) return die ('invalid session');
var userId = session.passport.user;
if (!userId) return die('no authenticated user in session');
... handling socket for authenticated user
});
Basically, it uses the session.socket.io module to propagate the session from the standard http requests (authenticated using passport) to the socket.io connection. And everything that isn't supposed to be provided by the user is taken from the session/db/server.

Related

SignalR multi user live chat desynchronisation

I have a live chat in which multiple people would be connected simultaneously. All public messaging works fine, but sometimes private messaging to a specific id doesn't work. I believe i narrowed it down to when people disconnected and reconnected that they connected to a different instance (perhaps IIS had recycled and started a new hub).
I thought I had fixed it, but I haven't and now I'm here because I'm stuck. What I thought would fix it was changing the connection variable within the startChat() function to refresh it with the correct information.
This is a cut down version of the code, as I didnt thing the rest would be necesary.
Issue is that when connected to signalR recipients of a message directly to them doean't come through, even though the chat Id it's being sent to it correct. Possible hub/socket mismatch?
var chat = $.connection.chatHub;
$(document).ready(function () {
// Start the chat connection.
startChat();
//restart chat if disconnected
$.connection.hub.disconnected(function () {
setTimeout(startChat(), 5000);
});
$.connection.hub.error(function (error) {
$('#messagebar').html('Chat ' + error + '. If this message doesn\'t go away, refresh your page.');
});
chat.client.addToChat = function (response) {
$('#chat-' + response.Type).prepend(response.Message);
};
});
function startChat() {
chat = $.connection.chatHub;
$.connection.hub.start().done(function () {
//get recent chat from db and insert to page.
//also saves user's chat id to their user for lookup when private messaging
$.ajax({
method: 'POST',
url: '/api/Chat/SetupChat/'
});
$('#messagebar').html('Connected to chat.');
});
}
Any help appreciated, Thanks.
Not sure exactly how your message is going missing, but you should send messages to a User instead of by connection id. This way you be able to identify on the server that a User has at least one connection, and send messages to all connections for that User. if a given connection id is no longer valid, but another one is (because the client has refreshed the page for example) the message wont be lost.
From the docs https://learn.microsoft.com/en-us/aspnet/core/signalr/groups:
The user identifier for a connection can be accessed by the
Context.UserIdentifier property in the hub.
public Task SendPrivateMessage(string user, string message)
{
return Clients.User(user).SendAsync("ReceiveMessage", message);
}
Not sure how this relates exactly to your server code, but you could add it if you're unclear how to progress.

unable to broadcast a user disconnection in socket.io

i am new to socket.io & nodejs. i have been writing a tictactoe game and i have a problem in it, my purpose is if someone refresh the page or close the browser let his/her opponent know . i know i should do this with disconnect event and here is what i try, but it is not working .
server side
socket.on('disconnect', function() {
socket.emit('user:disconnect');
});
client side
socket.on('user:disconnect', function() {
var message = player.getPlayerName() + ' leaves';
socket.emit('gameEnded', {room: this.getRoomId(), message: message,id:player.getPlayerId(),gameid: this.getGameId(),winType:"leave"});
});
also, i need to know how to get the room of disconnected user .
i already saw this but i just want to send the users in a room not all users in the whole application.
server.js
socket.on('disconnect', function() {
socket.emit('user:disconnect');
});
In the above code if a user named 'xxx' is disconnected, server is emitting 'user:disconnect' to the same user. You have to find the socket connection of other player and emit the event to that client.
You can achieve your goal by joining both the clients in a room and send message to other user in the room.
socket.join('room1');
io.sockets.in('room1').emit('user:disconnect');
Otherwise you have to store all clients as mentioned below and send message to the specific client using the following code.
var users = {
'client1': [socket object],
'client2': [socket object],
'client3': [socket object]
}
users['client3'].emit('user:disconnect')

How to use the correct protocol for receiving active mq web socket stomp from java based program

I have a JavaScript based active mq listener, who is using stomp and web sockets.I was able to send test messages to active mq and receive them.
What I really want is it needs to be sent from a Java based code.
Is it Ok to have the JavaScript listening on web sockets/stomp and
the java code be using tcp ?
If it is OK, should all of the ports be the same?
I am having issues receiving data in JavaScript. However I am seeing the topic being enquued in the active mq.thanks
function subscribeEndpoint(endpoint){
var client = Stomp.client("ws://localhost:61614/stomp", "v11.stomp");
var headers = { id:'JUST.FCX', ack: 'client'};
client.connect("admin", "admin", function () {
client.subscribe(endpoint,
function (message) {
alert(message);
}, headers);
});
}
Java:
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost:61616/stomp");
// Create a Connection
Connection connection = connectionFactory.createConnection();
connection.start();
// Create a Session
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
// Create the destination (Topic)
Destination destination = session.createTopic("vrwrThreat");
// Create a MessageProducer from the Session to the Topic or Queue
MessageProducer producer = session.createProducer(destination);
producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
// Create a messages
TextMessage message = session.createTextMessage(text);
producer.send(message);
// Clean up
session.close();
connection.close();
Clients can communicate with each other across protocols and transport mechanisms without issue. A STOMP client on WebSocket or any other port (TCP, SSL, etc) can send to a Topic and an AMQP, MQTT or OpenWire client can receive the message so long as the protocol supports the content of the message, same goes for the reverse case of AMQP, MQTT or OpenWire sending and STOMP receiving.
The case you've mentioned is pretty standard. The code you've posted appears to be using the OpenWire client to send to a Topic "vrwrThreat". The URI used in the connection factory is slightly off in that you added the '/stomp' which is meaningless. Since you are sending to a Topic you need to ensure that the client that is to receive the message is active at the time of transmission otherwise the message will be dropped. Also you need to ensure that both are operating on the same Topic which is unclear from your code snippets.

Socket.io reconnection causes new username

I am creating a chat in node.js and socket.io.
When a user opens my application, I ping the server and ask it to let the user join a specific room and set a random username (which can be edited at a later stage).
I use this
io.on('connection', (socket) => {
socket.on('join room', (roomId, callback) => {
// leave and join room
if (socket.roomId) {
socket.leave(socket.roomId);
}
socket.roomId = roomId;
socket.join(roomId);
// set username
if (!socket.username) {
socket.username = getRandomUsername();
}
});
});
It seems to work, but I have experienced situation where I have had the application running for a long time, and suddenly the user's username has changed.
I am suspecting this to occur because the user has lost connection, and socket.io have tried reconnecting. When the user has reconnected, the original socket is lost (and therefore it has no username), and a new username is assigned to the new socket, which overrides the original client socket.
Is there a problem with my code by assigning a random username to the user like this? It is somehow the same Google Docs does when the user is not signed in (they often give you an animal's name).
How can I solve the problem? I would very much like to avoid using cookies. An option could probably be to tell the client that it lost connection, and it has to reload the page, and then ask the server to get the same username.
I already save the assigned username on the client with this code:
const socket = io();
let username = null;
socket.on('connect', function() {
socket.emit('join room', roomId, function (newUsername) {
username = newUsername;
});
});
(...)

i would like to private message a user [duplicate]

I've beeen scouring the Net with no luck. I'm trying to figure out how to send a private message from one user to another. There are lots of snippets, but I'm not sure about the client/server interaction. If I have the ID of the socket I want to send to, how do I send it to the server, and how do I ensure the server only sends the message to that one receiver socket?
Is there a tutorial or walkthrough that anyone knows of?
No tutorial needed. The Socket.IO FAQ is pretty straightforward on this one:
socket.emit('news', { hello: 'world' });
EDIT: Folks are linking to this question when asking about how to get that socket object later. There is no need to. When a new client connects, save a reference to that socket on whatever object you're keeping your user information on. My comment from below:
In the top of your script somewhere, setup an object to hold your users' information.
var connectedUsers = {};
In your .on('connection') function, add that socket to your new object. connectedUsers[USER_NAME_HERE] = socket; Then you can easily retrieve it later. connectedUsers[USER_NAME_HERE].emit('something', 'something');
Here's a code snippet that should help:
Client-side (sending message)
socket.emit("private", { msg: chatMsg.val(), to: selected.text() });
where to refers to the id to send a private message to and msg is the content.
Client-side (receiving message)
socket.on("private", function(data) {
chatLog.append('<li class="private"><em><strong>'+ data.from +' -> '+ data.to +'</strong>: '+ data.msg +'</em></li>');
});
where chatLog is a div displaying the chat messages.
Server-side
client.on("private", function(data) {
io.sockets.sockets[data.to].emit("private", { from: client.id, to: data.to, msg: data.msg });
client.emit("private", { from: client.id, to: data.to, msg: data.msg });
});
Although we have nice answers here. However, I couldn't grasp the whole client server unique user identification pretty fast, so I'm posting this simple steps in order to help whoever is struggling as i did.....
At the client side, Get the user's ID, in my case I'm getting the username...
Client side user registration
//Connect socket.io
var systemUrl = 'http://localhost:4000';
var socket = io.connect(systemUrl);
//Collect User identity from the client side
var username = prompt('Enter your Username');
socket.emit('register',username);
The Listen to register on the server side to register user's socket to connected socket
Serve side code User registration
/*Craete an empty object to collect connected users*/
var connectedUsers = {};
io.on('connection',function(socket){
/*Register connected user*/
socket.on('register',function(username){
socket.username = username;
connectedUsers[username] = socket;
});
});
Send Message from the client side
$(document).on('click','.username',function(){
var username = $(this).text(),
message = prompt("type your message");
socket.emit('private_chat',{
to : username,
message : message
});
});
Receive message on server and emit it to private user
/*Private chat*/
socket.on('private_chat',function(data){
const to = data.to,
message = data.message;
if(connectedUsers.hasOwnProperty(to)){
connectedUsers[to].emit('private_chat',{
//The sender's username
username : socket.username,
//Message sent to receiver
message : message
});
}
});
Receive message on client and display it
/*Received private messages*/
socket.on('private_chat',function(data){
var username = data.username;
var message = data.message;
alert(username+': '+message);
});
This is not the best, however you can start from here....
The easiest way I can think of is to have an hash of all the users on using their id or name as the key and have their socket as part of the value then when you want to send a message to just them you pull that socket and emit on it... something like this:
users[toUser].emit('msg',"Hello, "+toUser+"!");
if you have a web site that has register users with uid then you can create a room for each user and name the room by uid of the user.
first connect client to the server using :
var socket = io('server_url');
on the server side create an event for detecting client connection:
io.on('connection', function (socket) {}
then you can emit to client inside it using socket.emit(); and ask uid of current user.
on the client side create an event for this request and then send uid of the user to server.
now on server side join the connected socket to room using :
socket.join(uid);
console.log('user ' + socket.user + ' connected \n');
now you can send private message to a user using following line:
io.to(uid).emit();
if you use the code above, it doesn't matter how many tab user has already open from your web site . each tab will connect to the same room.
in socket.io 1.0 use
io.sockets.connected[<socketid>]
you can store just socket id. like so:
var users = {};
users[USER_NAME] = socket.id;
then:
io.sockets.connected[users[USER_NAME]]
.emit('private', {
msg:'private message for user with name '+ USER_NAME
});
You can create an unique room for messaging between USER_A and USER_B and both users must join to this room. You may use an UUID as a ROOM_ID (the 'socketId' in the following example).
io.on('connection', socket => {
socket.on('message', message => {
socket.to(message.socketId).emit('message', message);
});
socket.on('join', socketId => {
socket.join(socketId);
});
});
See Joining Rooms and Emit Cheatsheet
The way I got it to work is by introducing one more event "registered user". This basically triggers on the client side as soon as there is a registered user and then emits this even and passes "currentUser._id"
Client Side:
var socket = io();
<% if (currentUser) { %>
socket.emit('registered user', "<%= currentUser._id %>");
<% } %>
Server Side: Once the "registered user" even triggers, it joins the current user socket to the new room with the name which is that user id. So basically each registered user will be in a room which is his/her uid.
socket.on('registered user', function (uid) {
socket.join(uid)
});
Server Side: One there is a message sent, I pass the id of the user the message is sent to in the msg object and then emit to that specific room.
// Private chat
socket.on('chat message', function (msg) {
const uidTo = msg.uidTo
socket.in(uidTo).emit('chat message', msg )
}); `
});

Categories