error sending header, express comparison code - javascript

I wondered. And in general, I need help.
app.get('/admin', async (req,res) => {
let tq = await User.findOne({ where: { link: req.params.userId } })
// if (tq.status === req.originalUrl.split('/')[1])
//myname(req, res)
return res.render('/admin')
// } else {
// res.end('w')
// }
}
if I do this, then I will not get mistakes. (spoiler: cors on)
async function myname(req, res) {
let tq = await User.findOne({ where: { link: req.params.userId } })
if (tq.status === req.originalUrl.split('/')[1]) {
next()
} else {
res.end('w')
}
}
//and I will connect it to the code above (imagine that there are no crutches, a regular render of the page
then we get an error of something type: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
what's my problem? Do I have to use conditional operators everywhere?...

Related

mongoose how to update an user profile with id

I created an simple CRUD operation in nodejs and mongoose. Updating an user using RESTAPI.
an error message in Insomnia
Error: Server returned nothing (no headers, no data)
URL
http://localhost:1337/api/users/update/63ab9b716065482273e58b75
#PUT METHOD
router.put("/update/:id",updateUser)
const updateUser = async (req,res,next) => {
if (req.params.id === req.user.id) {
try {
const updateuser = await User.findByIdAndUpdate(req.params.id, {
$set:req.body,
})
res.status(200).json(updateuser)
} catch (error) {
next(error)
}
}
}
how to updating with id of user
req.params.id will be of type string, while req.user.id will be probably of type ObjectId.
Can you try this:
if (req.params.id.toString() === req.user.id.toString()) {
As mentioned before req.user.id type is ObjectId. Also you should send an error when ids are not the same.
Example for your code:
const updateUser = async (req, res, next) => {
try {
if (req.params.id !== req.user.id.toString()) {
// Send error in here.
}
const updateuser = await User.findByIdAndUpdate(req.params.id, {
$set: req.body,
});
res.status(200).json(updateuser);
} catch (error) {
next(error);
}
};

Cannot set headers after they are sent to the client - Express JS

I am pretty much new to node / express and following a youtube tutorial to build a MERN Stack app. But my node server is giving this error
I tried restarting server many times it happening again and again. I got the idea it happens when we send two responses for one request but I don't think its the case here.
Btw here is the route it is pointing to in the error (in the try catch error response line)
// GET RANDOM
router.get("/random", verify, async (req, res) => {
const type = req.query.type;
let movie;
try {
if (type === "series") {
movie = await Movie.aggregate([
{ $match: { isSeries: true } },
{ $sample: { size: 1 } },
]);
} else {
movie = await Movie.aggregate([
{ $match: { isSeries: false } },
{ $sample: { size: 1 } },
]);
}
res.status(200).json(movie); //checked here by console logging it comes here only once
} catch (err) {
res.status(500).json(err); //the error pointing to this line
}
});
Just in case, here is the verify function code:
function verify(req,res,next) {
const authHeader = req.headers.token;
if(authHeader){
const token = authHeader.split(' ')[1];
jwt.verify(token,process.env.SECRET_KEY,(err,user) => {
if(err) res.status(403).json("Token is not valid");
req.user = user;
next();
})
} else{
return res.status(401).json("Unauthorized");
}
}

How to handle 401 error status code error in Node.js/Express?

I am working on login functionality in my project, now, flow looks like this (from front-end to back-end):
async login() {
await login({
password: this.userPassword,
login: this.userLogin,
twoFactor: this.twoFactor
}).then((res) => {
if (res.error) {
//
} else {
console.log(res)
}
})
}
And here is starts problems, as you can see if something goes wrong, I return status code 401 and some error message. When I login with correct data, there is no problem with getting token, but when I provide wrong data I have external pending login endpoint in development tools in browser and then, after some time, Error: Request failed with status code 401 in front end terminal. Without this status(401) with just JSON it works fine, but when I try to add 401 code, application crashes.
const userService = require('./../services/userService')
const crypto = require('./../services/cryptoService')
const jwt = require('./../services/jwtService')
const twoFactorService = require('node-2fa')
module.exports = {
login: async (req, res) => {
let { login, password, twoFactor } = req.body
password = crypto.encrypt(password, process.env.APP_KEY)
const result = await userService.getUserToLogin(login, password)
if (!result) {
res.status(401).json({
error: 'Unauthorized'
})
} else {
const faCode = result.twofatoken
const result2F = twoFactorService.verifyToken(faCode, twoFactor);
if ( !result2F || result2F.delta !== 0 ) {
res.status(401).json({
error: 'Unauthorized'
})
} else {
const userId = crypto.encrypt(result.id, process.env.CRYPTO_KEY)
const token = await jwt.sign({
uxd: userId,
});
res.json(token);
}
}
}
}
Actually, I have no idea on what to do with that and how to handle this error.
Ok, here is the answer. Actually, you just need to handle this error in your router:
router.post('/login', async (req, res) => {
try {
const data = await api.post('/login', req.body)
res.json(data.data)
} catch (e) {
// Probably you have here just console.log(e), but this way, you can handle it
res.status(e.response.status).json(e.response.data)
}
})

How to get user.id from jwt token in Node.js?

In my User controller, I create a token in which I save this user's id when he login to my application.
exports.findOne = (req, res) => {
User.findOne({
where: {
login: req.body.login,
},
})
.then(user => {
if (user) {
if (bcrypt.compareSync(req.body.password, user.password)) {
const token = jwt.sign(
{
id: user.id, // this is the id I need.
},
env.SECRET_KEY,
{
expiresIn: 129600,
},
);
return res.status(200).json({
message: 'Auth successful',
token,
});
}
...
}
})
.catch(err => {
res.status(400).json({ error: err });
});
};
Now in another controller I would like to read this id and use it for my purpose. How can I get to it?
const loginId = '?'; // here I want to give it to id
Bill.update(
{
available_funds: available_funds - amountMoney,
},
{ where: { id_owner: loginId } },
).then(() => {
res.status(200).send(`ok`);
});
Make a middleware which checks the incoming token before forwarding to your update route.
This middleware should be responsible for validating the incoming token which you pass from the client side code after logging in (storing token in cookies is commonly practiced).
Now in your middleware, you can do something similar to this:
app.use(function(req,res,next) {
JWT.verify(req.cookies['token'], 'YOUR_SECRET', function(err, decodedToken) {
if(err) { /* handle token err */ }
else {
req.userId = decodedToken.id; // Add to req object
next();
}
});
});
Then, finally in your upcoming controller, you can access the id from the request object:
const loginId = req.userId;
Bill.update(
{
available_funds: available_funds - amountMoney,
},
{ where: { id_owner: loginId } },
).then(() => {
res.status(200).send(`ok`);
});
You don't need to add extra codes. To access the userId use this:
req.payload.id

Writing jest test for chained functions in node.js

I have a function i want to test with jest, the function basicly does some token verifying and takes 3 params
this is de code of the function i want to test:
const verifyToken = (req, res, next) => {
// check header or url parameters or post parameters for token
var token = req.headers['x-access-token']
if (!token) return res.status(403).send({ auth: false, message: 'No token provided.' })
// verifies secret and checks expire date
jwt.verify(token, config.secret, (err, decoded) => {
if (err) return res.status(500).send({ auth: false, message: 'Failed to authenticate token.' })
//put user inside req.user to use the user in other routes
User.findById(decoded.id, (err, user) => {
if (err) {
return res.status(500).json({
message: err
})
} else if (!user) {
return res.status(404).json({
message: 'No user found'
})
} else {
req.user = user
}
next()
})
})
}
so i'm writing a first test, which tests if no token is given in de request, that it sends a 403 with a message. following is the test.
const verifyToken = require('../../config/token')
describe('veryfiy token tests', () => {
it('Should give 403 status when no token is present', () => {
let mockReq = {
headers: {}
}
var mockRes = {
status: code => code
send: message => message
}
let nextCalled = false
let next = () => {
nextCalled = true
}
expect(verifyToken(mockReq, mockRes, next)).toBe(403)
})
})
Now the test passes with an error:
TypeError: res.status(...).send is not a function
when i removed .send() from res.status in the code, the test passes.
I have been trying to figure out how to mock both status() and send() on the res object. but have not found a solution yet.
Tnx
I think the problem is that the result of res.status() does not have a function called send().
Try using this:
var mockRes = {
status: code => ({
send: message => ({code, message})
}),
};
You should be able to test with:
var result = verifyToken(mockReq, mockRes, next);
expect(result.code).toBeDefined();
expect(result.code).toBe(403);
PS: Haven't tested the code :)
you can make chained mock class and test, wether functions are executed or not.
here is an example.
class MockResponse {
constructor() {
this.res = {};
}
status = jest
.fn()
.mockReturnThis()
.mockImplementationOnce((code) => {
this.res.code = code;
return this;
});
send = jest
.fn()
.mockReturnThis()
.mockImplementationOnce((message) => {
this.res.message = message;
return this;
});
}
and now use this mock class to test. and check given function has executed with given result or not.
example like
it("should not call next function, and return 401, if token has not been found", async () => {
let res = new MockResponse(); // here i initialised instance of class
let next = jest.fn();
let req = {cookies:""} // header or cookies where you are receiving token here in my case empty.
await authentication(req, res, next); // here i used my mock res class
expect(next).not.toHaveBeenCalled(); // you must check that next will not be called.
expect(res.status).toHaveBeenCalledWith(401);//you can check result of status
expect(res.send).toHaveBeenCalledWith("not authenticated");// send() message in your function
});

Categories

Resources