-
-
Notifications
You must be signed in to change notification settings - Fork 327
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
createdAt field #12
Comments
I think you would have to use a submit button with The method would be something like this: Meteor.methods({
doInsert: function(doc) {
doc.createdAt = (new Date());
return MyCollection2.insert(doc);
}
}); Autoform validates on the client and the server before ever calling your method, so you know MyCollection2.beforeMethod = function (doc, method) {
if (method === "doInsert") {
doc.createdAt = (new Date());
}
return doc;
} One thing I'm wondering is whether setting it on the server is necessary. I thought Meteor had some built-in date saving magic that made sure local dates set on the client were saved in proper UTC on the server. I'm not sure I ever fully understood how they're doing the dates. |
I think we must clearly distinguish
Of course, those two objects are linked. The Form constructor function can take a schema as a parameter. So let's consider again the
Collection methods (insert/update/delete) are safe. What about Meteor methods?
And here is the implementation (autoform-server.js):
Now, imagine that my
and then my To put it in a nutshell:
|
Interesting. Good catch on the security issue. I can think of another way to fix it, though. When you create a new AutoForm or Collection2 object, there can be a "methods" option that allows you to specify which methods can be called with that schema. MyFormA = AutoForm(schemaAObj, {methods: ["methodA"]});
MyFormB = AutoForm(schemaBObj, {methods: ["methodB"]}); Then _autoFormCheckFirst: function(method, objName, doc) {
var obj = global[objName];
if (!obj) {
throw new Error("No object exists on the server with that name.");
}
if (!obj.allowsMethod(method)) {
throw new Error("That method may not be called with the given schema.");
}
checkSchema(doc, obj.simpleSchema());
return Meteor.call(method, doc);
} Now this would work: Meteor.call("_autoFormCheckFirst", "methodA", "MyFormA", docThatMatchSchemaA); But this would not: Meteor.call("_autoFormCheckFirst", "methodA", "MyFormB", docThatMatchSchemaB); As for the form vs. collection vs. schema aspect, I agree that these are separate ideas, which is why I decided to make three separate related packages instead of one, but I also wanted to make things as simple as possible, which is why there is an AutoForm object that closely resembles the Collection2 object. In truth, AutoForm adds very little to the SimpleSchema object, so I generally think of them as the same thing. Despite it's name AutoForm is really just a schema that is specific to one or more forms. Maybe it should be called FormSchema instead. The reason for having it instead of using the SimpleSchema object directly is to provide additional form-specific options, such as my proposal above for defining allowed methods, which is not something that would make sense to do directly on SimpleSchema. So other than fixing that security/data integrity issue with |
So, again, Meteor methods must always check (or checkSchema) their arguments (that's why the |
So I will:
I think that's it to fix this issue. I can address the scoping issue separately. |
Ok for [2] and [3]. For [1], validate forms on the server is useless, it doesn't add security at all. In others words, Meteor methods arguments are never trusted (because one can manually do a A form is just a UI to get an object in client JavaScript memory. And client objects can never be trusted. |
You're not really validating the form on the server, you're validating the object that was passed in against the schema. That's precisely what you're arguing must be done. It's no different than calling It's true that you don't need to do it if your method is working with a collection2, but what about the example of a contact form? The AutoForm object: ContactForm = new AutoForm({
name: {
type: String,
label: "Your name",
max: 50
},
email: {
type: String,
regEx: SchemaRegEx.Email,
label: "E-mail address"
},
message: {
type: String,
label: "Message",
max: 1000
}
}); The HTML: {{#autoForm schema="ContactForm" id="contactForm"}}
<fieldset>
<legend>Contact Us</legend>
<div class="form-group{{#if afFieldIsInvalid 'name'}} has-error{{/if}}">
{{afFieldLabel "name" class="control-label"}}
{{afFieldInput "name"}}
{{#if afFieldIsInvalid "name"}}
<span class="help-block">{{afFieldMessage "name"}}</span>
{{/if}}
</div>
<div class="form-group{{#if afFieldIsInvalid 'email'}} has-error{{/if}}">
{{afFieldLabel "email" class="control-label"}}
{{afFieldInput "email"}}
{{#if afFieldIsInvalid "email"}}
<span class="help-block">{{afFieldMessage "email"}}</span>
{{/if}}
</div>
<div class="form-group{{#if afFieldIsInvalid 'message'}} has-error{{/if}}">
{{afFieldLabel "message" class="control-label"}}
{{afFieldInput "message" rows="10"}}
{{#if afFieldIsInvalid "message"}}
<span class="help-block">{{afFieldMessage "message"}}</span>
{{/if}}
</div>
<div>
<button type="button" data-meteor-method="sendEmail" class="btn btn-primary">Submit</button>
<button type="reset" class="btn btn-default">Reset</button>
</div>
</fieldset>
{{/autoForm}} The Meteor method: Meteor.methods({
sendEmail: function(doc) {
checkSchema(doc, ContactForm.simpleSchema());
var text = "Name: " + doc.name + "\n\n"
+ "Email: " + doc.email + "\n\n\n\n"
+ doc.message;
this.unblock();
Email.send({
to: "test@example.com",
from: doc.email,
subject: "Website Contact Form - Message From " + doc.name,
text: text
});
}
}); In the Meteor method, the call to |
Now you've got me thinking. I don't think collection2 methods are actually secure either. Both client and server just check the doc against the schema and then call the normal collection insert/update/remove. This means that one could insert into the wrapped collection1 and the insert would happen on the server, too, without validation. The client could be made secure by calling a proxy meteor method that does the insert, but it would also have to disallow client side modification of the collection. I think I'll need to include some schema checks in the allow/deny for the wrapped collection1 when c2 creates it. I'm going to have to give this a lot more thought. |
Regarding the C2 security issue, see issue Meteor-Community-Packages/meteor-collection2#5. I figured out a fix. |
Here is my API proposition for the same contact form: https://gist.github.com/mquandalle/6284027 |
OK, that's helpful. I see what you're proposing. I think that should all be fine. I will probably continue to support passing in the string name of a global AutoForm object for backwards compatibility, but there is nothing preventing handlebar binding now that the automatic server check is gone. |
That's great! Here is the same proposal binding code for "two forms in one" issue #6:
I agree that you can easily support backwards compatibility by checking if the first argument is a string or not. |
In a Collection2 model I have defined a required field named
createdAt
wich is a simple Date object. How can I create an object on the client with autoform, add thecreatedAt
field with the current date on the client, and then overwrite this field on the server to get the trust-able date value?Maybe extract and modify the schema:
Give this
schema
to an autoform and then run a Meteor.method on both the client and the server to add thecreatedAt
attribute?The text was updated successfully, but these errors were encountered: