Skip to content

Adjusted Minimongo to prohibit dot based field name inserts, to fix issue #3786#8169

Merged
benjamn merged 5 commits intometeor:develfrom
hwillson:issue-3786
Jan 3, 2017
Merged

Adjusted Minimongo to prohibit dot based field name inserts, to fix issue #3786#8169
benjamn merged 5 commits intometeor:develfrom
hwillson:issue-3786

Conversation

@hwillson
Copy link
Copy Markdown
Contributor

@hwillson hwillson commented Dec 19, 2016

Hi all - this PR is intended to help address issue #3786. Right now Minimongo allows inserts with dot (".") containing field names, which is against Mongo's field name restrictions. The changes in this PR will cause a new exception to be thrown if dot containing field inserts are attempted by Minimongo, with the exception thrown matching the exception thrown by Mongo on the server side. Thanks!

@hwillson
Copy link
Copy Markdown
Contributor Author

Hmm - Travis failed but from the error log the failures don't look like anything caused by this PR?

@hwillson
Copy link
Copy Markdown
Contributor Author

Okay, it is my fault - ecmascript is missing (thanks @abernix)! Fixing now.

Comment thread packages/minimongo/minimongo.js Outdated
// field name restrictions:
// https://docs.mongodb.com/manual/reference/limits/#Restrictions-on-Field-Names
if (doc) {
const invalidFieldMatches = JSON.stringify(doc).match(/"([^"]*\.[^"]*)":/);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I believe this RegEx might be susceptible to match inadvertently on the value side.

Consider the JSON:

{"value":"silly quoted JSON in here \"︵ (°.°)/ ︵\": inadvertently matches!  eeps"}

...which I believe would throw the error incorrectly.

As an alternative, thoughts on using the replacer function of JSON.stringify?

JSON.stringify(doc, (key) => {
  if (key.indexOf(".") > -1) {
    throw MinimongoError(`Field ${key} must not contain '.'`);
  }
  return value;
});

We could fix the regex, but I'm just thinking that the built-in function might be faster anyway and more able to handle whatever is thrown at it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Awesome idea! I'll make that change - thanks!

@RobertLowe
Copy link
Copy Markdown
Contributor

Does this check for .s or does this check for any non-sane mongo field name which may be the larger issue? I'm not sure .s are the only problematic character, we may want a charlist/wordlist or this could be fine to merge as just a one off until someone complains of the ladder

Nice effort 👍

@abernix
Copy link
Copy Markdown
Contributor

abernix commented Dec 20, 2016

I'm assuming dots are the most commonly encountered reason, but it's reasonable to say that this could/should be expanded to prevent the other disallowed configurations: null characters or starting with a dollar sign. I'm not sure if anything outside of those three things would be a problem though.

@hwillson
Copy link
Copy Markdown
Contributor Author

Hi guys - yes, this PR was just addressing the original issue of '.''s. That being said it would be pretty trivial to extend it to handle $'s and null characters, so I'll make it happen - thanks for the feedback!

@hwillson
Copy link
Copy Markdown
Contributor Author

Whoa - @abernix, check out the "All checks have passed" section of this PR. My last commit just completely by-passed CircleCI:

screenshot 2016-12-20 10 19 16

I know why - I originally started this PR with my own instance of CircleCI running checks, then disabled my CircleCI instance just before the last commit, to speed up the CI run using Meteor's CI instances. The act of disabling it then committing means I've just been able to by-pass the CircleCI tests completely, and we're all green! Looks like yet another security hole caused by Circle allowing developer CI instances to override project CI instances 😞 ...

@mitar
Copy link
Copy Markdown
Contributor

mitar commented Dec 20, 2016

I have not checked code, but $rename operator should probably also check that you are renaming to a valid name? (If that was allowed before.)

@hwillson
Copy link
Copy Markdown
Contributor Author

Hi @mitar - good point; I just ran some tests with $rename and Minimongo. If you try to rename a field to a new field with a ., it creates a new nested field/object, so I think we're okay there. If you try to rename a field to a new field with a $, Minimongo throws a Uncaught Error: can't set field named $a exception so we're okay there as well. If you try to rename with a null byte however, Minimongo does let it go through! So it looks like we should track down and adjust renames to restrict null bytes. I'll dig in an update this PR as needed. Thanks for the additional insight!

@mitar
Copy link
Copy Markdown
Contributor

mitar commented Dec 21, 2016

Hm, maybe then also looking into $set would be beneficial.

BTW, I opened many tickets about difference between client and server side in the past: https://github.com/meteor/meteor/issues?q=is%3Aissue+is%3Aopen+minimongo+author%3Amitar

You could look into them. How I caught them: I made tests run on client and server. So Meteor tests on the client, and Minimongo tests against the server. I think this should be done and would catch many many differences already. See also closed issues which were not all addressed: https://github.com/meteor/meteor/issues?q=is%3Aissue+minimongo+author%3Amitar+is%3Aclosed

@hwillson
Copy link
Copy Markdown
Contributor Author

hwillson commented Dec 22, 2016

Hi all - I've adjusted $rename to make sure it doesn't allow null bytes. @mitar - I had previously verified $set doesn't allow dot characters, so no changes were necessary. I just checked for $'s and null bytes; $'s are prohibited but null bytes are currently allowed as well! My recent changes include a patch for this. I've also reviewed all other Minimongo insert/update combinations that would allow invalid field names, and I think we're now covered. So this PR should now fully address the original issue (plus $'s and null bytes).

With regards to other differences between Minimongo/Mongo, I know - I've been watching several of your issues. I believe that's a can of worms for another day/PR though ...

Thanks again all!

@mitar
Copy link
Copy Markdown
Contributor

mitar commented Dec 22, 2016

You are amazing! Thanks so much!

@mitar
Copy link
Copy Markdown
Contributor

mitar commented Dec 22, 2016

And for other issues, I think the best first step would be to start running tests on both client and server side for Mongo related stuff.

Copy link
Copy Markdown
Contributor

@abernix abernix left a comment

Choose a reason for hiding this comment

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

This looks great. Nice work, @hwillson (& everyone!)

@benjamn benjamn merged commit d831785 into meteor:devel Jan 3, 2017
@hwillson hwillson deleted the issue-3786 branch January 4, 2017 13:51
@dreich-nucleus
Copy link
Copy Markdown

This is a little late, but there was an unintended consequence of this fix. When doing an upsert where the query/selector has dotted keys, the upsert fails with the "MinimongoError: Key must not contain '.'" error.

collection.insert({ val: 100, ref: { b: '123abc', desc: 'ref to other obj' }})

collection.upsert({'ref.b': '345xyz'}, {$set: {val: 1000}, $setOnInsert: {ref: {...full info}}})

The selector is a valid query and the update code will add the selector to the doc to ensure a second upsert actually finds the new document. But it just adds the ref.b to the update doc and that blows up in the insert.

We are still stuck on a fairly old meteor (1.4.2) which actually works with the above code because the minimongo version is 1.0.19. However, something in our full unit test suite is pulling in a slightly newer version (1.0.21) and the unit tests fail. Makes it a little tough to deliver code to master when the tests fail. When we upgrade to a newer version, this issue might get worse.

@RobertLowe
Copy link
Copy Markdown
Contributor

@dreich-nucleus in the meantime you could use collection.rawCollection() to access the native mongo driver and consider updating

@dreich-nucleus
Copy link
Copy Markdown

The unit tests are mocking the real collections as in memory collections - I did not think rawCollection was available on those.
There is a project to upgrade to 1.7 but that won't land before my project is done. I do have a workaround though. It looks like the issue has been fixed in the latest code though.

@mitar
Copy link
Copy Markdown
Contributor

mitar commented Mar 19, 2019

@dreich-nucleus I think you should open a new issue about this.

@dreich-nucleus
Copy link
Copy Markdown

I could do that, but what if it is fixed in 1.7? It would be my first issue here and I don't want to make a silly one. Advice is welcome.

@mitar
Copy link
Copy Markdown
Contributor

mitar commented Mar 19, 2019

I think better to comment in already closed PRs is to open an issue. Report in which version you are finding this problem (this is part of good issue) and yes, maybe it will be closed if it is fixed in newer version. But it will definitely get more eyes if it is a new issue and not discussion inside something already closed.

@dreich-nucleus
Copy link
Copy Markdown

Sounds good. I figured the context would be helpful, but I will link this discussion to the new issue. Thanks

@dreich-nucleus
Copy link
Copy Markdown

Looks like the issue was #8631 (#8631). Sadly, that issue never came up on my searches. Oh well.

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.

6 participants