Sending data to a independent remote server - node.js

I want to send a json object to another server, independent of my website.
The API I am using requires a user (user x in this case) to log into their service to be authorized so user x can manipulate user x's list. However, other users can't write to x's list. So, users need to request an item to be added to x's list, then a server who is logged into x's account can add it to x's list. Refer to the image below.
http://imgur.com/a/wT53t
I am using node/express.js for the servers on the user's side. However, I don't know what I should use for a server who's only job is to receive requests and write to x's list. Can you provide some guidance as to how I can achieve something like this?
Thanks!

There are two options here:
You have to refresh the list in the realtime for connected users.
To achieve this you should use either: WebSockets(e.g. socket.io) or LongPolling.
In second option you dont have to refresh the list in the realtime. You simply use express. Accept data and refresh the list server-side.
Auth with web sockets:
Once understanding the nature of web sockets, you're free to build any logic around them, including authentication/authorization. The great library doing lots of auth things is passport.js.
Very quick and abstract example of server-side:
socket.on('auth', function(data) {
const vendor = data.vendor,
token = data.id
switch(vendor) {
/*
Here you grab through some social API user social id
and save it to database
*/
}
/* set socket as logged in */
socket.logged = true
/* or even save user object */
socket.user = { vendor, token }
})
Next time you need authorized user, you check:
socket.on('mustBeAuthorized', function() {
if(socket.logged || socket.user) {
/* Continue your logic*/
}
})

Related

Getting the 'current user' in an emit listener in nestjs app

My nestjs + React app has a Google oauth flow loosely based on this process. One thing that the Google library tries to help with is to take a refresh_token (that you've likely stored in your app's db) and use it to automatically retrieve a new access_token if the old one is expired. When it does this refresh, it emits a 'tokens' signal, and in my code I need something like
oauth2Client.on('tokens', async (tokens) => {
if (tokens.refresh_token) {
// store the refresh_token in your secure persistent database
console.log(tokens.refresh_token);
}
console.log(tokens.access_token);
});
It appears that the Google library intentionally does not let you proactively make a call to do the token refresh. The refresh happens automatically when you've set a refresh_token on the oauth2 client object and use that client object to next make any Google API call where the previous access_token has expired.
What I'm finding tricky is that when the above listener runs, I ideally would be able to get the 'current user' whose initial client session is what led to this server code path running. I can certainly create a chain of events like
User is logged into my app on the client
User does something on the frontend
A call to the server is made that has #UseGuards(AuthGuard()) and where I can get the user from the #Req
The above controller calls some additional functions, one of which can use the oauth2 client to make any random Google API call
If the random Google API call caused a token refresh, it would run the listener quoted above.
...but then, when #5 happens, is there any way to get the user detected in #3? Perhaps put another way, is there any way to 'inject' more info when the certain signal is emitted (but it's emitted in the Google library, not my code), or is there a way for the listener to pull the user from some kind of context?
(In case it matters, the emitter looks like this)

Is there something I can use to uniquely identify a device connecting to a socket with Socket.IO?

I'm working on an app that keeps users together in a room using socket.io. While using the app, I'm keeping track of actions the users take. If a user disconnects accidentally (in my use case, their phone rings, or the screen shuts off), I want them to be able to re-enter the room as the same 'user' without requiring a login so the actions they've tracked stay with them. I tried using socket.conn.remoteAddress, but that doesn't seem to be consistent enough to rely on.
For now, I'm requiring the user to manually enter a username and match to the user with that name on the server, but I'd rather it be automatic and invisible to the user, not to mention more reliable than what each user inputs.
Use a cookie. When they connect, check if their unique cookie already exists. If not, create it with a unique ID in it. If it does already exist, use the unique ID in it to identify the user.
From the connect event in socket.io, you can get the cookies here.
const socketCookieName = "socketUser";
const cookieParser = require('socket.io-cookie-parser');
io.use(cookieParser());
io.on('connection', function(socket) {
// all parsed cookies in socket.request.cookies
let user = socket.request.cookies[socketCookieName];
if (!user) {
// create unique userID and set it in a cookie
user = /* create some unique userID here */;
// set this into a cookie
}
// now user will be your socket.io userID
});

How to preserve Socket.io sockets app-wide

I am trying to add socket.io functionality to my App.
I have never used socket.io before, so I have no idea how to progress from here.
I've used the MERN Stack until now, and the next step would be to implement socket.io for chat functionality. The problem is, I don't know when to connect, and how to preserve my sockets. The user can sign in, so I thought I could just connect after signing the user in, but then the socket is created in a component, and I can't access it from anywhere else.
The problem is, I use JWT tokens for authentication, so I have a function, that "signs the user in" when going to a new page, if the token hasn't expired yet.
if(localStorage.jwtToken){
const token = localStorage.jwtToken;
setAuthToken(token);
const user = jwt_decode(token);
store.dispatch(action_setCurrentUser(user));
store.dispatch(setGroupsOfUser({ id: user.id }));
const currentTime = Date.now() / 1000;
if(user.exp < currentTime){
store.dispatch(logoutUser());
window.location.href = './login';
}
}
I thought I could just connect in here, but then my ChatView component can't access it to send messages and stuff. I need a socket to send notifications, even if the user isn't in a chat room, and the ChatView component needs it to send messages.
Tried to connect after the login dispatch, and store the online users on the server, with their socketIDs.
If I try to search for a solution, every hit I get is about authentication using socket.io, but the authentication is already done for me so I'm not sure how to proceed.
As suggested, I decided to create the socket in my App.js and store it in my state.
I can use this stored state then in my subcomponents, and assign it on the server to a user after sign in.
You might want to look in redux. Since your having all the auth stuff and all . It might get messy handling app wide authentication .

How to create multiple instances of nodejs server

I am building a notification application in which every time an event is triggered the associated user gets a notification. I am using localstorage of NodeJs to store the information of the logged in user. The problem is that when two users are logged in,the localstorage values are overridden by the new users value.
I need to create multiple instances of NodeJS server so that every user has its own localStorage.
For example
If two users log in with credentials
{
userName:name1
}
and
{
userName:name2
}
then two separate localStorage should be created one having userName:name1 and one having userName:name2.
I have tried all the solutions available online but I am unable to create multiple states of NodeJS server.
Thanks in advance
You do not have to create a new server for each user. Take the IP address and port instead. This means that each user can be uniquely identified. You can simply name the files of the users after the variable client.
Here an example code
net.createServer((netSocket : net.Socket) => {
netSocket.on('data', (data) => {
var client = netSocket.remoteAddress + ':' + netSocket.remotePort;
})
})
I wasn't able to create multiple nodejs instances hence I stored the user data in session storage and passed it to nodejs server every time I triggered a request.

Meteor - Check if user is logged in as administrator (Client - Side)

I'm currently developing an app which needs users and administrators. What I do right now is, I create an admin account on the client with username 'admin' and a default password that should be changed over the accounts-ui.
I do this because creating a user like this:
Accounts.createUser({
username : 'admin',
email : 'test#test.com',
password : 'changethispasswordovertheuserinterface',
profile : { type : 'admin' }
});
doesn't work for me on server side. That means I just create the admin in my client.js and just use this code to check if the admin is logged in.
Template.admin.isAdmin = function () {
var currentUser = Meteor.user();
// Is this hackable?
if (null !== currentUser) {
if ('admin' === currentUser.username) {
return true;
}
}
};
Is this the best way to approach this? And most importantly, is my site hackable like this (Could somebody fake it)?
Yes this is hackable, one could pull up the chrome inspector and modify this quite easily. Or even faster, by typing something like Template.admin.isAdmin = function () { return true; } into Chrome's web console
The best approach would be to only provide the information to the client from the servers end if the user is an admin. So this would mean using Meteor.allow to ensure the database can only be changed by an administrative user, if peforming ops from the client end.
It also depends a bit on what you want to use 'isAdmin' for too. If its content, you could generate the html on the server's end and send it down to the client in a Meteor.methods. At the moment the templating system doesn't provide for locking down the UI on the clients end depending on what the user's document contains.
For any administrative commands, you could use a Meteor.call at which point the user is vetted on the server's and and the transaction is performed there.
The answer on this thread works too AND the top-voted answer has code for a server side, Meteor method call.

Resources