Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

400 Bad Request for invalid database names #214

Open
wants to merge 6 commits into
base: master
Choose a base branch
from

Conversation

gr2m
Copy link
Contributor

@gr2m gr2m commented Feb 22, 2017

I would argue this is not a breaking change as it only fixes a bug to make express-pouchdb behave like CouchD. The side effect of this is that if a datbases that included special chars before were used they will now appear empty. E.g. "user/abc456" would have been stored as "userabc456" and will now be stored as "user/abc456". Renaming the files manually before restarting should fix the problem

closes #213

}
};
}
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’m not sure if there is a more efficient way to do this. We could for example find all internal /_* paths once and store it in some kind of app state to make the lookup immediate without the need to traverse to all routes every time

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, It might be better to just create a object hash with the routes on startup and we just look at that here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Happy to change that, but I would need guidance on how to do that

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this solution seems a bit heavy. A simpler solution may be to check for all usages of new PouchDB() and isolate your logic to that. AFAICT this is only done in one single place, which is packages//node_modules/express-pouchdb/lib/create-or-delete-dbs.js, so you should be able to isolate your fix there.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah actually I see now why you had to do this; you need to send the 400.

I agree that looping through all routes for every single request seems like a potentially slow design, though. I'd prefer a more elegant solution but you'd probably have to dig through the code to see how Marten set up the routes because I'm not an expert in that.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@marten-de-vries: hmm I was not aware of PouchDB.new(); my goal with create-or-delete-dbs.js was to avoid memory leaks caused by creating new PouchDBs for every request. It seems that logic should be unified.

@gr2m I hadn't thought about that use case. You essentially want new PouchDB('user/foo') to map to express-pouchdb's user%2Ffoo. I think that may be impossible given that the standard logic for new PouchDB('some/really/long/path/here') is that it literally maps to a deep path somewhere, whereas express-pouchdb explicitly wants to avoid that... So it seems you would need to do new PouchDB('user%2Ffoo') within your app.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nolanlawson are you sure? When I removed the filename sanitation then it worked all perfectly fine, without needing to do anything like new PouchDB('user%2Ffoo')

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a good reason that that particular filename sanitization is in there, though; you wouldn't want users to be able to create a DB called ../../etc/passwords for instance. I think this needs a lot more thought and testing, and I'm also concerned about backwards compat. If we're going to break users who used to rely on new PouchDB('foo/bar') not actually creating a foo/ directory then it should at least be a major version release.

In any case all of this code is very hairy and lacks tests, so maybe that's the first problem we should attempt to solve...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

../../etc/passwords would fail the regex ^[a-z][a-z0-9_$()+/-]*$

it should at least be a major version release.

Yes, agree. But you mentioned that’s no problem

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah okay, that makes sense. And yeah 3.0.0 is no problem, just want to make sure that we finally fix db name escaping this time. 😃

Copy link
Member

@garrensmith garrensmith left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is really helpful. Nice work @gr2m. I don't know this well enough to approve. It would be nice to get @nolanlawson feedback as well

if (route) for (var j = 0, method; j < route.stack.length; j++) {
method = route.stack[j].method.toUpperCase()
if (method === req.method && route.path.substr(1, dbName.length) === dbName) {
console.log('ok?')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can remove this

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lol yes

}
};
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, It might be better to just create a object hash with the routes on startup and we just look at that here.

route = app._router.stack[i].route;
if (route) for (var j = 0, method; j < route.stack.length; j++) {
method = route.stack[j].method.toUpperCase()
if (method === req.method && route.path.substr(1, dbName.length) === dbName) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really understand express internals, why do you need to check the method as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That’s actually a good question. I think we don’t have to, now that I think about it :) I thought I had a case in mind why we need this, but can’t recall

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think you do if you go this way. You're checking if the current method is the same as the method of the route you're trying to match. If you don't check, it would allow you to do things like POST /_all_dbs (which is nonsensical).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah that was my thinking, but if you disallow /_all_dbs for all methods, you don’t have that problem. And I think there should be no problem with that

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True, but you'd have to do that explicitly, which is messy as you might forget it somewhere. Now PouchDB itself might do that itself for databases starting with _, in which case you are right. But that's too long ago for me to recall.

}
};
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this solution seems a bit heavy. A simpler solution may be to check for all usages of new PouchDB() and isolate your logic to that. AFAICT this is only done in one single place, which is packages//node_modules/express-pouchdb/lib/create-or-delete-dbs.js, so you should be able to isolate your fix there.

package.json Outdated
@@ -58,7 +58,6 @@
"pouchdb-vhost": "^1.0.2",
"pouchdb-wrappers": "^1.3.6",
"raw-body": "^2.2.0",
"sanitize-filename": "^1.6.1",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One problem with removing sanitize-filename entirely is that it was doing some extra work for us to ensure that e.g. files named PRN or CON don't break on Windows (see this page; you really cannot create files or directories with those names)

This might be considered a minor thing, but if you run pouchdb-server on Windows and users can crash your system by creating DBs named PRN then it's kind of a big deal 😅

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmmm that’s a tough one. Would you be okay to simply forbid this names altogether for now for the time being? I’ll create an issue and log an error linking to it. Because renaming the db name internally will again break the initial reason why I want to fix this.

It seems like this is something that should be fixed on PouchDB adapter level

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that's a good point. new PouchDB('prn') currently breaks in LevelDB-based PouchDBs, which is not express-pouchdb's fault. We could just throw an error on Windows. 🤷‍♂️

}
};
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah actually I see now why you had to do this; you need to send the 400.

I agree that looping through all routes for every single request seems like a potentially slow design, though. I'd prefer a more elegant solution but you'd probably have to dig through the code to see how Marten set up the routes because I'm not an expert in that.

@gr2m gr2m force-pushed the 213/db-name-validation branch 2 times, most recently from d93a549 to bbe30e6 Compare June 15, 2017 15:51
@gr2m
Copy link
Contributor Author

gr2m commented Jun 15, 2017

hey @nolanlawson @garrensmith.

I’ve made lookup more efficient, it is now happening once on start up, I think that addressed all concerns? The remaining one is to release a breaking version with this change. What is our process for this?

@gr2m gr2m force-pushed the 213/db-name-validation branch from bbe30e6 to f9c7cc9 Compare June 15, 2017 16:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

express-pouchdb: removes "/" from db names
4 participants