How to get logged in user in adonis js websocket controller - websocket

I am trying to get the current logged in user details in a websocket controller. I tried like this
constructor ({ socket, request , auth}) {
this.socket = socket
this.request = request
this.auth=auth
}
async onClose (data) {
const user = await this.auth.user
console.log(user) // it gives null
}
I get null. How can I get the user details?
Thank you.

Since you have assigned auth object to controller's auth variable, i assume you have added the middleware to the routes in the socket.js file. if you have done that already, you can try the following line
async onClose (data) {
//const user = await this.auth.user
const user = this.auth.user // this.auth.user will give you anything you want
const id = user.id
const name = user.name
console.log(user) // it will console the authenticated user details
}
Hope it will help.

Related

Iron session is not updating req.session object

I have a page where users can give themselves a "role" like member or admin. They can go to another route to create messages. I am trying to update user's role from "user" to "admin". It updates req.session to admin role in the admin.js file, but when I go to messages/create.js and try to log req.session, it shows that user still has the "user" role. I am saving the changes I make by calling req.session.save(), but it is not working.
admin.js
import { withIronSessionApiRoute } from "iron-session/next";
import nc from "next-connect";
import { session_config } from "../../lib/config";
import Users from "../../models/user";
import { connectToDatabase } from "../../util/mongodb";
const handler = nc()
handler.post(async (req) => {
if (req.body.password === process.env.ADMIN_PASSWORD) {
await connectToDatabase()
await Users.findOneAndUpdate({ name: req.session.user.name }, { role: "admin" })
const updated_user = { name: req.session.user.name, role: "admin" }
req.session.user = updated_user
await req.session.save()
}
})
export default withIronSessionApiRoute(handler, session_config);
messages/create.js
import { withIronSessionApiRoute } from "iron-session/next";
import nc from "next-connect";
import { session_config } from "../../../lib/config";
const handler = nc()
handler.post(async (req) => {
console.log(req.session.user)
console.log(req.body)
})
export default withIronSessionApiRoute(handler, session_config)
Please let me know what the issue is and how I can fix it. Thank you
The first thing I noticed from looking at the code is that you're not sending a response back to the client. Iron session uses cookies to manage stateless authentication and the way it manages is by setting the response header. Because you're not sending a response, it can't update the session.
Looking further into the API documentation, session.save() - "Saves the session and sets the cookie header to be sent once the response is sent."
Not knowing your full implementation or having a working code example from something like codesandbox.io, I suggest the following code to see if this solves your problem.
// please make sure that `res` is a parameter on the `.post()` function
// on your original code. I've already set it as shown below.
handler.post(async (req, res) => {
if (req.body.password === process.env.ADMIN_PASSWORD) {
await connectToDatabase()
await Users.findOneAndUpdate({ name: req.session.user.name }, { role: "admin" })
const updated_user = { name: req.session.user.name, role: "admin" }
req.session.user = updated_user
await req.session.save()
// response below
res.send({ ok: true })
// or if you don't want to send custom data back, comment the line above,
// and then uncomment the line below
// res.status(200).end()
}
})
Attempt 2
I made an iron session demo on Codesandbox using some of the demo code from the iron session repo NextJs example.
The code example shows:
login
log out
setting a user as an admin
fetching user data from server-side
fetching user data from client-side
fetching using SWR
Some side notes to be aware of: if you are doing something like
const sessionData = req.session.user, then trying to mutate the req.session.user, and then sending the data back, it won't work because the session object will be recreated per request and node cannot store req.session as a reference.
If my demo doesn't help you, then you're going to have to share more info and code, and maybe create a Codesandbox to reproduce what is happening to you.

Window object is undefined after deploy to netlify

I want to build an email verification. After the user registers, the user gets an email and clicks on it for verification purposes. The email-link invokes a netlify lambda function (api end point). Inside the link is a jwt token, which I decode on the backend. I used
window.location.href
for it and sliced the part I needed and decoded it. On localhost, it works fine, however, if I deploy it to netlify, I get an
window is undefined
error. I read that you have to check for
typeof window !== 'undefined'
However, if I add that to my lambda function I don't get any console.log statements.
exports.handler = async (event, context, callback) => {
if (typeof window !== 'undefined') {
let url = window.location.href
let index = url.indexOf("=");
let token = url.slice(index+1)
console.log(token, 'token here')
const decoded = jwt.verify(token, process.env.SECRET);
console.log('confirm registration route triggered',decoded)
if (decoded) {
const { email } = decoded;
console.log(decoded, 'decoded here')
User.findOneAndUpdate({email: email}, {verified: true },(...e)=>{
console.log(e)
});
} else {
console.log('could not update user')
//redirect user to page with message about email confirmation link expiration
//and proposal to register again
}
console.log('confirm registration got invoked')
}
return {
statusCode: 400,
body: "Oops"
}
};
I read that the function first runs on the server when deployed and afterwards on the client. Seems like it does not run on my client, as I invoke the api-endpoint directly? I'm quite a beginner when it comes to API-Endpoints, thanks for reading!
In case you have the same issue when deploying to netlify, you have to run
event.queryStringParameters
which gives you access to the query parts of your url.

Send param with POST to Botframework (and different channel)

I'm working on bot project, the bot are going to work on different channel (web/messenger and probably other)
I'm actually at the proactive message, we want to send dynamic message to user, for example "You don't talk me from XXX time"
So I've made a new route in bot, for sending message with conversation references, it's work good on emulator/messenger for the moment, but we trying to add parameter to this request but we don't found any way to get param in bot.
server.post('/api/notify/:conversationID', async (req, res) => {
console.log(req)
if (req.params.conversationID){
console.log(req.params.conversationID)
}
for (let conversationReference of Object.values(conversationReferences)) {
if (typeof conversationReferences[req.params.conversationID] !== "undefined"){
await adapter.continueConversation(conversationReferences[req.params.conversationID], async turnContext => {
await turnContext.sendActivity(req.params.message);
});
}else {
await adapter.continueConversation(conversationReference, async turnContext => {
await turnContext.sendActivity(req.params.message);
});
}
}
res.setHeader('Content-Type', 'text/html');
res.writeHead(200);
res.write('<html><body><h1>Test send.</h1></body></html>');
res.end();
});
I also tried with GET, and sending parameter in URL like /api/notify/CONVID/MESSAGEtoUSER
But if the message length are more than 70 character, the bot return automatically method don't exist, it's like when the length are 'big' so but understand it like route and not like parameter...
Anyone have idea how can we get the param?
Thank!
EDIT :
Finally I found a way to pass param as POST call.
You need to enable bodyParser of restify, add this line :
server.use(restify.plugins.bodyParser())
in index.js
You can now get the body of POST route call !
:-)
You can achieve this by passing any params in an empty activity via the channelData property. Because the activity includes an empty string in the text property, the activity will not display when passed to the bot.
In this example, the proactive message is initiated from the browser.
server.get('/api/notify/:userId', async (req, res) => {
const { userId } = req.params;
for (const conversationReference of Object.values(conversationReferences)) {
await adapter.continueConversation(conversationReference, async turnContext => {
var reply = { type: ActivityTypes.Message };
reply.channelData = { userId };
reply.text = '';
await turnContext.sendActivity(reply);
});
}
res.setHeader('Content-Type', 'text/html');
res.writeHead(200);
res.write('<html><body><h1>Proactive messages have been sent.</h1></body></html>');
res.end();
});
Proactive message sending the userId via channelData
userId is received by the bot via activity.channelData
Testing Web Chat also shows userId in the activity.channelData
Hope of help!

Sending message from Cognito triggers

I want to restrict user sign-ins from Cognito hosted UI. I can see there are triggers in which we can attach lambda, but whenever I change event object inside of lambda, instead of getting my custom message User exceeded limits, I get unrecognizable lambda output error.
Can anyone help me in this or is there any other way to achieve this functionality?
Now,I'm getting this
with this code :
exports.handler = (event, context, callback) => {
if (true) {
var error = new Error("Cannot signin because your signin count is 5");
// Return error to Amazon Cognito
callback(error, event);
}
// Return to Amazon Cognito
callback(null, event);
};
But,I don't want prefix PreAuthentication failed with error,I just want to display my message.
Any help is appreciated.
Currently, there is no way to stop Cognito from adding the prefix because the form is a hosted web UI.
If this is a hard requirement, the workaround is to create your own login form and use the aws-cognito-sdk
Once you make the call to cognitoUser.authenticateUser in the code below the Pre authentication trigger will fire the Lambda function and you will need to handle the error and parse it to remove the unwanted prefix.
Hope this Helps
aws Examples: Using the JavaScript SDK
var authenticationData = {
Username : 'username',
Password : 'password',
};
var authenticationDetails = new AmazonCognitoIdentity.AuthenticationDetails(authenticationData);
var poolData = { UserPoolId : 'us-east-1_TcoKGbf7n',
ClientId : '4pe2usejqcdmhi0a25jp4b5sh3'
};
var userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);
var userData = {
Username : 'username',
Pool : userPool
};
var cognitoUser = new AmazonCognitoIdentity.CognitoUser(userData);
cognitoUser.authenticateUser(authenticationDetails, {
onSuccess: function (result) {
var accessToken = result.getAccessToken().getJwtToken();
/* Use the idToken for Logins Map when Federating User Pools with identity pools or when passing through an Authorization Header to an API Gateway Authorizer*/
var idToken = result.idToken.jwtToken;
},
//Your message from the Lambda will return here, you will need to parse the err to remove the unwanted prefix*
onFailure: function(err) {
alert(err);
},
});

abort all Axios requests when change route use vue-router

how can i abort / cancel Axios request before complete when i change route use
vue-router.
when user open page it automatically send axios request to get some data,
but user don't waiting to get response then he is changing route by vue-router
it will be a lot of Axios requests
so is there any solve to my problem
Update: Axios (0.22.0+)
CancelToken is now deprecated. Check #m0r answer for updated solution using AbortController. Here is the link from the official documentation:
https://axios-http.com/docs/cancellation
Original answer
Basically you have to generate a global cancel token
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
and use it in all your requests by passing it in the config parameter
GET request:
axios.get('/user/12345', {
cancelToken: source.token
}).catch(function(thrown) {
if (axios.isCancel(thrown)) {
console.log('Request canceled', thrown.message);
} else {
// handle error
}
});
POST request:
axios.post('/user/12345', {
name: 'new name'
}, {
cancelToken: source.token
})
Then, within a vue-router beforeEach navigation guard you can cancel all requests using:
source.cancel('Operation canceled by the user.');
Here's the official axios guide for cancellation: https://github.com/axios/axios#cancellation
Answer from #fabruex is correct. I just wanted to add here that if you have lot of api calls then you have to pass cancellation token in each api call config. In order to reduce that code, you can create axios instance and add request interceptor which will add that common cancellation token and then you can assign a new value to token when cancellation is done or your route has changed.
// Some global common cancel token source
let cancelSource = axios.CancelToken.source();
// Request interceptor
export const requestInterceptor = config => {
config.cancelToken = cancelSource.token;
return config;
};
// Add request interceptor like this
const request = axios.create({ baseURL: SOME_URL });
request.interceptors.request.use(requestInterceptor);
// Now you can use this axios instance like this
await request.get('/users');
// and
await request.post('/users', data);
// When you will cancel
cancelSource.cancel('Your cancellation message');
// And all the api calls initiated by axios instance which has request interceptor will be cancelled.
Edit to answer #Suneet Jain
You can create a class and create an instance which you can update
class CancelToken {
constructor(initialValue) {
this.source = initialValue;
}
getSource() {
return this.source;
}
setSource(value) {
this.source = value;
}
cancel() {
this.source.cancel();
}
}
export const cancelSource = new CancelToken(axios.CancelToken.source());
You can import that instance cancelSource and call cancel when required e.g. when you logout, you can call to cancel all request which have cancellation token given by cancelSource.getSource()
So after logout
cancelSource.cancel('CANCELLED');
And when again user will login, set new cancellation token to this global instance
cancelSource.setSource(axios.CancelToken.source());
2022 Update | Axios (0.22.0+)
CancelToken is deprecated. AbortController should be used now in new projects. The implementation is cleaner.
const controller = new AbortController();
Pass the controller in the config parameter:
axios.get('/foo/bar', {
signal: controller.signal
}).then(function(response) {
//...
});
And to cancel the request, simply use:
controller.abort()
source : https://github.com/axios/axios#cancellation

Resources