Inserting password reset token to unprotected NodeJS route - javascript

I am currently trying to pass my password reset generated token inside my unprotected route but whenever I execute my GET request, I receive an 401 Unauthorized request.
I've tried including the package Path-to-RegExp and constructing a separate array route but it didn't work:
let tokens = [];
const unprotected = [
pathToRegexp('/user/reset/:token', tokens),
];
My password-reset token is generated in a separated service and called in a controller:
const token = crypto.randomBytes(20).toString('hex');
user.update({
resetPasswordToken: token,
resetPasswordExpires: Date.now() + 360000,
});
Here is how I've structured my expressJwt with unless:
app.use(expressJwt({
secret: process.env.SECRET_BEARER,
getToken: req => {
MY TOKEN AUTHORISATION CODE IS PLACED HERE.
}
}).unless({ path: ['/images/', '/user/password-reset', unprotected ]}));
My issue is that whenever I try to create a unauthenticated route such as .unless({path: ['/images/', '/user/password-reset', '/user/reset/:token' ]})); the route /user/reset/:token is only parsed as a string a the value of :token is not actually passed.
I've read some similar questions about passing it with regex or functions but I couldn't figure it out myself. This and this question have been particularly useful on how to approach the problem.

You can pass a regex to unless, which you may have already realized since you tried to use Path-to-RegExp. You could also just try to write the regex yourself and pass it directly to unless. In your case your unless would look like this:
.unless({ path: [/\/images\//, /\/user\/password-reset\//, /^\/user\/reset\/[a-z0-9_-]*/]}));
EDIT: this SO answer suggest that you cannot combine regex and strings in the same array, so I've converted all paths to regex expressions.

You have an array within an array for the value of path passed into unless.
Change:
}).unless({ path: ['/images/', '/user/password-reset', unprotected ]}));
To:
}).unless({ path: unprotected }));
And change unprotected to include the other paths:
const unprotected = [
'/images/',
'/user/password-reset',
pathToRegexp('/user/reset/:token', tokens),
];
Ensure you test with a path that includes a token e.g:
/user/reset/123-some-real-looking-value

Related

Extract the common query path from RESTFUL URL (Ablate the resources) JS

I have a RESTFUL url design like this: GET /street/:streetName/house/:houseNumber or GET /street/:streetName/house/listings. As you can see, the :streetName and :houseNumber are resource names. I am trying to extract the static (common) parts from the url for some following logics which means I want to get /street/house and /street/house/listings (ablate all resources parts in the url).
I was trying to find a JS lib for this but didn't find one. Any pointers?
PS: I can do some string matching to achieve this like split by "/" then concat them and only care about the key words, so I can ignore all resource names. But this doesn't seem robust.
Assuming you have a route for each URL pattern, you can set an additional property req.staticParts in each middleware:
app.get("/street/:streetName/house/:houseNumber", function(req, res, next) {
req.staticParts = "/street/house";
...
})
...
.get("/street/:streetName/house/:houseNumber/listings", function(req, res, next) {
req.staticParts = "/street/house/listings";
...
})
.use(function(req, res) {
additionalLogic(req.staticParts);
});
This avoids string operations and is very explicit, therefore very robust.
Parsing the URL into staticParts without knowledge of the routes is problematic. For example, parsing the URL /street/house/25 based on keywords would lead to req.staticParts = "/street/house", but there is no matching route for it.

Can you tell me if express-mongo-sanitize is working?

I'm trying to set up some security middleware for my humble little MERN web app, and I'm currently using helmet and express-mongo-sanitize, specifically for protection against NoSQL injection attacks.
I've set it up, however, as below in my server.js file:
const express = require('express')
const helmet = require('helmet')
const mongoSanitize = require('express-mongo-sanitize')
...
app.use(mongoSanitize())
app.use(helmet())
// Routes below
...
I've tried to test it by making a mock sign up like:
username: {"$gt": ""}
password: 'TestPassword'
so that req.body would be:
{
username: '{"$gt": ""}',
password: 'TestPassword'
}
but express-mongo-sanitize doesn't seem to be catching it and it goes through to my database. Am I misunderstanding something? The value of the username key is a string, so maybe it's already OK? Please forgive my ignorance, I'm learning.
What express-mongo-sanitize does is sanitize keys that start with a dollar sign.
username: '{"$gt": ""}' --> this isn't a key starting with a dollar sign. Rather, the value of username is just a string.
Try sending it this object instead:
{
"username": { "$gt": "" }
}
From what I understood, from debugging and going through the code, the keys it sanitizes is any potential key in a key=value pair of query & post params that have the $ or a dot. It also tries to sanitize any keys in the body and header of the request.
For example, even the json provided by the previous user above won't do it.
but https://your-domain/?$user=json would be sanitized to user=json.
It doesn't remove $ from the value of the params as you and also I was expecting. I also opened up a question on the github to the creator and will see what he says. I would think the security risk is for both the key and value. This doesn't do any good if you're not saving the key to mongodb but saving the value instead.
For reference it checks the following HTTP sections to remove any potential harmful $ or .
['body', 'params', 'headers', 'query'].forEach(function (key) ...
I think the answer by #A10n is correct, and so it appears that 'express-mongo-sanitize' is only a partial solution. I've added my quick-and-dirty solution to remove curly brackets from every req.body/params object (which should blunt most NoSQL attacks) like so:
// Middleware that replaces all {} symbols with [] to prevent NoSQL attack
const removeCurlies = (req, res, next) => {
Object.keys(req.body).forEach((key) => {
req.body[key] = _.replace(req.body[key], "{", "[");
req.body[key] = _.replace(req.body[key], "}", "]");
});
Object.keys(req.params).forEach((key) => {
req.params[key] = _.replace(req.params[key], "{", "[");
req.params[key] = _.replace(req.params[key], "}", "]");
});
next();
};
Then, before your routes:
app.use(removeCurlies);
Ran into the same problem and what worked for me was parsing the incoming request body before using the mongoSanitize package. Like this...
const express = require("express")
const mongoSanitize = require("express-mongo-sanitize')
const app = express()
app.use(express.json())
app.use(mongoSanitize())

Complex redirect in vue router

I am using vue-router on a multipage app; we are adding history mode because our requirements insist our urls not contain special characters (#) and want to ensure from within our frontend code that we are always prepending our clientside routes with /v/. (to avoid having to update all our routes in the whole app, and to centralize this functionality).
I want to add a route similar to:
routes: [
// add `v/` to paths that don't start with `v/`
{
path: `(^\/(?!v))*`,
redirect: to => `/v/${to}`
},
]
Based on using regex inside path-to-regexp, but I'm not entirely clear from their documentation how to properly pass in a whole route as a regex (or is it possible?), especially without getting caught in a redirect loop.
I was able to use 2 redirects to achieve what I needed (in this case falling back to '/' as a sort of 404.
// Fallback to baseRoute for prefixed unmatched routes
{ path: `${prefix}/*`, redirect: '/' },
// Fallback to baseRoute for unprefixed, unmatched routes (try again with prefix)
{ path: `*`, redirect: to => prefix + to.path }
(An interesting gotcha is that in a redirect function the to value remains unchanged if you get redirected, so I originally had an infinite loop. with to => to.path.startsWith(prefix) ? '/' : prefix + to.path)

How to use parameters containing a slash character?

My MongoDB keys in person collection are like this:
TWITTER/12345678
GOOGLE/34567890
TWITTER/45678901
...
I define getPersonByKey route this way:
router.route('/getPersonByKey/:providerKey/:personKey').
get(function(req, res) { // get person by key
var key = req.params.providerKey + '/' + req.params.personKey;
// ...
}
);
Of course I'd prefer to be able to write something like this:
router.route('/getPersonByKey/:key').
get(function(req, res) { // get person by key
var key = req.params.key;
// ...
}
);
But this doesn't work, since GET http://localhost/getPersonByKey/TWITTER/12345678 of course results in a 404, since the parameter with the slash is interpreted as two distinct parameters...
Any idea?
Express internally uses path-to-regexp to do path matching.
As explained in the documentation, you can use a "Custom Match Parameter" by adding a regular expression wrapped in parenthesis after the parameter itself.
You can use the following path to get the result you need:
router.route('/getPersonByKey/:key([^/]+/[^/]+)').
get(function(req, res) { // get person by key
var key = req.params.key;
// ...
}
);
You can test and validate this or any other route here.
You can use this if your parameters has containing slashes in it
app.get('/getPersonByKey/:key(*)', function(req, res) { ... })
It works for me (at least in Express 4). In my case, I used parameters like ABC1/12345/6789(10).
Hopefully this useful.
app.get('/getPersonByKey/:key(*)', function(req, res) { ... })
This isn't working for me.
Swagger-ui will encode the path var before using it.
e.g. article/2159 will become article%2F2159.
When going directly with curl, it will not get encoded. the slash will remain a slash instead of %2F. And then the route is not matched.
Update: I'm on fastify. On express 4.X this works correctly.

'or' query with different data types in sails.js

Given routes
GET /user/42
GET /user/dude
where 42 is user id and dude is username.
So, I want to have method in my controller that return user for both cases. Here it is:
// api/controllers/UserController.js
findOne: function(req, res) {
User.findOne({
or: [
{id: req.params.id},
{username: req.params.id}
]
}).exec(function(err, user) {
if (err) {
return console.log(err);
}
res.json(user);
});
},
When I try to GET /user/42 everything is fine.
When I try to GET /user/dude I get error:
Error (E_UNKNOWN) :: Encountered an unexpected error
error: invalid input syntax for integer: "dude"
It seems like sails refuses to process {id: 'dude'} because of type mismatch.
I am using sails 0.10.5 with sails-postgresql 0.10.9. So what am I doing wrong?
UPD: I do know how to solve problem. Of course I can put if statement to my controller and check what type of parameter it got. Actually, I just created two routes with regexp parameters that point to single method.
My actual problem is why I can not do this with or. Does sails provide such way?
By default, sails get method only supports id numbers. You will need
to define custom routes and implement the relevant api method to
support a get request using a string instead of a number.
Technical Details:
To solve your exact problem, you need to define the following route in your routes.js
module.exports.routes = {
...
'/user/get/:param': 'UserController.findByIDorName',
...
}
This will pass anything after the /user/get/ as the parameter named 'param' to the findByIDorName controller method.
Next you need to check the type of the param and decide if you want to fetch the user info based on the id or the name, so add this function in your userController.js
findByIDorName : function (req, res) {
if (isNaN(req.param)){
//find the user by his username after any validation you need
}
else {
//find the user by his id and return
}
}

Categories