express middleware not sending response - express

I have a delete route that has 2 middleware functions Authcontroller.protect and authcontroller.restrictTo("admin, "lead-guide")
router
.delete(
authController.protect,
authController.restrictTo("admin", "lead-guide"),
tourController.deleteTour
);
Within restrictTo I have a check to see if the user has the proper "role" to perform that task and if they don't, express is supposed ot send a 403. I'm seeing that express never actually sends the response. it enters the if statement(i see the console successfully printing fialure) and then it just skips sending the response.
exports.restrictTo = (...roles) => {
return (req, res, next) => {
console.log(req.user.role);
if (!roles.includes(req.user.role)) {
console.log("failure");
return res.status(403).json({
status: fail,
message: "you do not have permission to perform this action"
});
console.log(req, res);
}
next();
};
};

Put a try/catch in your inner function and see if there's an exception being thrown.
From looking at your code, if the fail variable (which you don't show a definition for) is not defined, then that would throw an exception and keep the res.json() from executing.

Related

Post Confirmation ConfirmForgotPassword lambda execution returns InvalidLambdaResponseException - Unrecognizable lambda output

I have spent a bunch of hours to solve this issue, all related SO answers seem to be outdated or irrelevant.
State:
Amplify.js "^4.3.10" with code
Auth.forgotPasswordSubmit(email, confirmationCode, password)
.then(_ => this.notification.success("Confirmation OK"))
.catch(err => console.log(err));
Lambda on Node.js 14
Cognito trigger "Post confirmation"
Lambda function code:
'use strict';
exports.handler = async (event, context, callback) => {
if (event.triggerSource === "PostConfirmation_ConfirmForgotPassword") {
const postConfirmEmail = () => `<html><body>HERE IS MY TEMPLATE</body></html>`;
event.response = {
emailSubject: "Reset Password Notification",
emailMessage: postConfirmEmail()
};
callback(null, event);
}
};
As result, I am getting
InvalidLambdaResponseException: Unrecognizable lambda output (Error 400)
The thing is that password is really updating as expected, but e-mail confirmation is NOT sent and error remains.
TIP: User is CONFIRMED. Tried also with "context.done(null, event);" / "return event;" but response is always with the same error.
You shouldn't be using an async handler with the callback. It's either one or the other.
Simply return event without calling the callback or don't make your function async.
Additionally, Cognito will not send confirmation emails, you will have to implement this functionality yourself.

How can I fix an Axios interceptor causing property 'status' of undefined error

I have a selection to set permissions for elements to global or private. I'm using the Axios interceptor request to handle looking for the permissions field to have data and, if it does, stringify it. The problem is, it causes me to get a "TypeError: Cannot read property 'status' of undefined" when I attempt to reload the program at all. The only "fix" right now is to log out, remove the interceptor, log in, read it, and then run the check again.
Because of this, I can't even get to the home dashboard of the software. If I clear my cookies, I can go back to the login screen, but no further than that after attempting to log in.
Is there something I'm missing for it? below is the interceptor code. If more information or context is needed, please let me know.
export default {
install: (Vue) => {
Vue.$eventBus = new Vue();
Vue.axios.interceptors.response.use(response => {
return response.data;
}, async error => {
if (error.response.status === 401 && error.config.url != '/api/authentication/login') {
var config = await Vue.$configService.find();
window.location = config.accountPortalUrl;
return
}
console.log(error);
Vue.$eventBus.$emit('notifyUser', 'Uh oh, something went wrong!');
return Promise.reject(error);
});
Vue.axios.interceptors.request.use(
config => {
// check request method -> use post if many params
if (config.data.permissions) {
config.data.permissions = JSON.stringify(config.data.permissions);
}
console.log(config);
return config;
}
);
}
};
Looks like your service API is not responding, this might happen if the user is not authenticated . Your error is at line where you check (error.response.status). Its only possible to get an undefined response when the request was interrupted before response. Most probably if you check your browser network pannel you will see that the preflight check for this request causes a 401 network error. Hence because the preflight failed your actual response comes as undefined. You should sanity check first if your server responded with a response or not and then access the response status.
Something like this might help
if (error.response) {
// Request was made and the server responded successfully
// You can now de-structure the response object to get the status
console.log(error.response.status);
} else if (error.request) {
// request was made but not responded by server
console.log(error.request);
}
So, the answer ultimately was something extremely simple.
if (config.data.permissions)
needed to be
if (config.data && config.data.permissions)

Getting error code 500 no matter what error I send from express using a error handler?

Using a custom error handler, specifically ts-custom-error but even when I roll my own, if I throw the following error after my routes to handle when someone puts in the wrong url/endpoint
app.use((req, res, next) => {
throw HttpError.fromCode(404)
});
app.listen(port, err => {
if (err) {
return console.error(err);
}
return console.log(`server is listening on ${port}`);
});
*edit added additional code
https://github.com/adriengibrat/ts-custom-error/blob/master/src/example/http-error.ts
I get the error message and stack ok, everything works in postman and browser for the body message, but in network on chrome and in the header it still shows a status code of 500. What am I missing?
Can you check your console/terminal for logs? 500 (Internal Server Error) means that there is something wrong with your server. Usually, an unhandled exception.
Are there any other code after this block? If not, your thrown error never gets handled anywhere, causing the 500 error.
You can use this instead:
res.status(404).send({ error: 'Your special error message here!' });

Express route : control flow with router.use/all and router.param

I would like to validate params using these kind of middleware. The problem is that router.param is always applied before the first middleware router.all (I also tried with router.use, it doesn't work because the param is common to both middlewares). Is there a way to execute Middleware 1 before router.param ?
// Middleware 1
router.all('/:firstId/checklist/:**secondId**/*',
(req, res, next) => {
console.log('Request matched')
next()
},
param('**secondId**', "Error message 2")
.isMongoId(),
checkValidationErrors
)
router.param('**secondId**', callback)
However, Middleware 1 does not work as I expected. If the param is a valid MongoDB ObjectId, 'Request matched' is logged, the next middlewares are applied accordingly depending on the request. If it is not a valid id, 'Request matched' is NOT logged, the expected error is NOT sent in the response. I get this error instead from Mongoose which comes from router.param :
MongooseError [CastError]: Cast to ObjectId failed for value "xxx" at path "_id" for model "XXX"
I tried to comment router.param and it solved the problem. So it is certainly related to the order of execution.
Thank you very much for your help
Flip this (The reason is in your case express is only looking for :firstId/* in both cases because it does fit for both scenarios. if the first pattern/path matches with the input URI, it does not go look for your middleware 2.
// Middleware 1
router.all('/:firstId/*',
param('firstId', "Error message 1")
.isMongoId(),
checkValidationErrors
)
// Middleware 2
router.all('/:firstId/checklist/:secondId/*',
(req, res, next) => {
console.log('Request matched')
next()
},
param('secondId', "Error message 2")
.isMongoId(),
checkValidationErrors
)
To
// Middleware 2
router.all('/:firstId/checklist/:secondId/*',
(req, res, next) => {
console.log('Request matched')
next()
},
param('secondId', "Error message 2")
.isMongoId(),
checkValidationErrors
)
// Middleware 1
router.all('/:firstId/*',
param('firstId', "Error message 1")
.isMongoId(),
checkValidationErrors
)
I could not find a way to use a middleware with the same parameter as router.param and execute it before router.param, since router.param seems to be executed first systematically. But there is a workaround to be able to do this : regrouping middlewares which you want to execute before router.param in a separate file.
Instead of :
app.js (main app file) routing to originalRouter (original router file).
The control flow should be :
app.js (main app file) routing to beforeParamMiddlewwareRouter routing to originalRouter (original router file)
OR
In app.js :
app.use('/path', beforeParamMiddlewwareRouter, originalRouter)
Feel free to offer a better solution if you have one. I am open to suggestions.

Error Handling ExpressJS and MongoDB

What is the suggested way of error handling in ExpressJS and Mongoose.
app.get('/', function(req, res) {
Subjects.find({}, function(err, subjects) {
if (err) {
return res.json(err);
}
res.render('list', {subjects: subjects});
});
});
I just returned the error in json. Any suggestions? Thanks
It depends on what that error is, but I would usually redirect via res.redirect to an 'Error' url, with details of the error.
You could test for the details of the error, and re-run a query (dependent on what the error is of course) but usually if the callback is throwing an error, it's terminal, so log it, redirect, and inform the user in a nice way.
(Or of course, return JSON and handle your response client side, with no redirect)
EDIT
As per comment from Paul -
I didn't mean to return the exact details to the user about the error.
Simply "Database error" or something like that would be more appropriate, depending on what the error was.