Server side HTML Form validation? - validation

I was wondering if it is possible to validate a container bound htmlService HTML Form server-side with GAS, to prevent a User from entering Invalid Data into a sheet, for example.
If it is possible to handle the form validation server-side, how would one go about doing so?

Google Apps Script hasn't a built-in way to do server-side form validation. You have to design the way that the form validation will be handled and how the feedback will be given to the web-app user.
A very simple validation might be to validate that the form submission has all the fields.
/**
* Put this in a .gs file. It might be called from the client-side
code
* by using google.script.run, using withSuccessHandler to handle
the boolean response.
*/
function validate(formData){
const expectedFields = ['field1','field2'];
const formFields = Object.keys(formData);
const isValid = expectedFields.every(field => formFields.includes(field))
return isValid;
}
/**
* Call this from a form submit event on the client-side.
* Usually this kind of code is included in a .html file between <script> tags.
*/
function handleFormSubmit(){
google.script.run
.withSuccessHandler(validity => {
if(validity){
// put here the code to confirm the that the form submission is valid
} else {
// put here the code to confirm the that the form submission is not valid
}
})
.withFailureHandler(error => {
// put here the code to handle server-side errors
}).validate(event.currentTarget)
}
There are some frameworks and communities around them that might help you on this task, i.e, Bootstrap, jQuery. Also there several are forms for sharing code like Node.js among many other that could have libraries / modules / packages that might be used with Google Apps Script.
Please bear in mind that doing server-side form validation in Google Apps Script might make your web app respond slowly as google.script.run (required for server-client communication) might be slow due to multiple factors, being one of them calling Google Apps Script services like SpreadsheetApp.
One trick that might help you handle the data-validation work is to write the validation rules some way that they could be used on the client and server sides. One way to do this is by using a .gs file to hold the JavaScript and use ScriptApp.getResource(filename).getDataAsString(), an undocumented method that have being working for years, to get this code and to insert it into a HtmlOutput object either by using a templated HTML or by using HtmlOutput.append(addedContent).
Related
JavaScript: client-side vs. server-side validation
Where do you record validation rules for form data in a web application?
Is it possible to read the contents of a Google Apps Script from another Script
Google App Script request validation on server

Related

Symfony2 : Best way to check form, client side

I'm developing a form with Symfony2 : several text inputs and one file input (for one picture). I have defined some asserts (maxLength, minLength...) in my entity in order to check the form (isValid).
My problem is : if the user puts bad data in text input (text too long or too short...), he still can submit the form, and error and printed but the user have to re-choose his picture.
As I think it's impossible to keep the picture in the form after bad validation, I should maybe check the form in client side (javascript), before submit.
So, is there an automatic way to do this (to forbidden submit until data are correct)? Can we get the assert minLength, maxLength value in twig ?
Thank you !
Ben.
You can use js validation before submitting the data, using some js form validation tools, but this way you need the replicate the validation logic from the server, so if validation rules changes, you need to modify on both server and client side. I recommend this method to reduce the traffic between client-server.
If you don't want this, use ajax form submitting (example here). You still validate the form using symfony, but the page won't refresh, so you won't lose the attached file. But this generates additional traffic to server, and you also need to implement error displaying using javascript.

Dynamically add form to formset in Django and submit with AJAX

I have read a lot of answers relating to how to dynamically add forms to an model formset in Django and can successfully implement that. However, I would now like to submit the formset with AJAX. This is mostly working now but I have an issue that I can't find a solution to in any other answer:
If you dynamically add a form to the formset, you give it a new form id number that is one larger than the maximum the form currently has and you also increment the management TOTAL_FORMS count by one. The newly added form then saves successfully as a new object.
I am trying to submit by AJAX so the user can continue editing without having the page refresh. The formset saves fine but any dynamically added forms are now existing objects. To account for this I need to increment the INITIAL_FORMS count on the management form when the save is successful. Easy enough. However, I've also realised I need to give the newly created objects an ID since they now exist in the database.
How can I get my view to tell me the ID of the new objects in its response to the AJAX call? Or is there a better way of looking at this?
Django forms and formsets are intended for classic browser-based posting of data. Though they can definitely be made to work with Javascript, the more you want to part from the normal behavior, the more complex it gets.
Depending on your requirements, you might start thinking about dropping it and switch to Javascript + REST endpoint. Of course, if you need progressive enhancements and you are required to have it work without javascript, that's not an option.
In any case, you want to have a customized view for posting from JS, so that you can get the result back and parse it easily in your AJAX handler. Probably some JSON.
There are several approaches you could take.
Have your AJAX send data to a different URL. This is pertinent if you have an API or are planning to build one at some point. So your form, when submitted normally, will do its old-style processing but your AJAX will talk to the API endpoint instead.
For instance, your form send to https://example.com/myform, but your Javascript code talks to REST api at https://example.com/api/v1/mymodel/ (sending PUT, POST and DELETE requests as appropriate).
Or if you don't have an API and building one seems overkill, you may just alter your view so it formats its output differently depending on whether the data is being submitted in the regular way or using AJAX.
You'd go about it like this:
class MyFormView(.....):
def render_to_response(self, context, **kwargs):
if self.request.is_ajax():
return self.render_to_json(context, **kwargs)
return super().render_to_response(context, **kwargs)
def render_to_json(context, **kwargs):
data = {
# see below!
}
return HttpResponse(
content=json.dumps(data).encode('ascii'),
content_type='application/json',
)
This is just an outline. You need to ensure is_ajax will detect it properly (see django doc). And you need to properly build data from context: extract the things you want to send back to your JS code and put them in the dict.
You will find it's manageable if you just do this for one, maybe two views in your project, but very quickly you'll want to have a small API instead, especially given how easy it is to build one with packages such as Django REST framework.
In your view, where you save the object, AFTER the save, the object.id will contain the new id for the object, which you can return via json or however you want in your ajax response, and then yes you will need to fill that into the formset row so that it will be submitted the next time.
One thing you have to watch out for is that django expects all existing rows to be at the top of the formset, and any new rows to be at the bottom. Otherwise, the formset save will complain about missing id's. So if you're doing any kind of sorting in your javascript, you can't do that.. unless you do quite a bit of fixing of all the field names etc in the formset. The formset code uses the numbers in the management form to determine which rows to insert and which rows to update, it does not do it on the basis of whether or not an id is present. Unfortunately...

How do I prevent tampering with AJAX process page?

I am using Ajax for processing with JQUERY. The Data_string is sent to my process.php page, where it is saved.
Issue: right now anyone can directly type example.com/process.php to access my process page, or type example.com/process.php/var1=foo1&var2=foo2 to emulate a form submission. How do I prevent this from happening?
Also, in the Ajax code I specified POST. What is the difference here between POST and GET?
First of all submit your AJAX form via POST and on a server side make sure that request come within same domain and is called via AJAX.
I have couple of functions in my library for this task
function valid_referer()
{
if(isset($_SERVER['HTTP_REFERER']))
return parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST) == $_SERVER['SERVER_NAME'];
else
return false;
}
function is_ajax()
{
$key = 'HTTP_X_REQUESTED_WITH';
return isset($_SERVER[$key]) && strtolower($_SERVER[$key]) == 'xmlhttprequest';
}
You might read this post regarding difference between post and get
While as Jason LeBrun says it is pretty much impossible to prevent people simulating a form submission, you can at least stop the casual attempts to. Along with implementing Nazariy's suggestions (which are both easy to get round if you really want to), you could also generate some unique value on the server side (i'll call it a token), which gets inserted into the same page as your Ajax. The Ajax would would then pass this token in with your other arguments to the process.php page whereupon you can check this token is valid.
UPDATE
see this question with regards to the token
anti-CSRF token and Javascript
You can not prevent people from manually emulating the submission of form data on your website. You can make it arbitrarily more difficult, but you won't be able to prevent it completely.

Validate data from CakePHP form with jQuery (AJAX)

I would like to validate both single field and multiple field data from a CakePHP form.
The single field validation should be done on blur from each field while the multiple field validation should be done on submitting the form.
I would like to use the $validate property declared in the Model for validating data and I would like to display the errors near each field (single field validation) and on top of the form (for multiple field validation).
My main goal is to achieve this the most "caky" way (if there is one for validating data with jQuery). I couldn't find any useful advice out there and I'm asking you for some help to get this going.
One of my concerns is how shall I pass data from the form to jQuery and then to the action that does the validation and also how shall I return and display the errors, if there are any.
Thank you in advance!
I'd suggest first making sure everything works without jQuery, then use the jQuery Form plugin to submit your forms via AJAX. If you include the RequestHandler component in your AppController, you should find that your controllers distinguish automatically between AJAX and synchronous requests.
OK, so I coded my own solution to this, but I am still waiting for a more "caky" approach.
I made two generic jQuery functions, one for single field validation and one for multiple field validation. The function should grab the data from the specified form and send it to the form's action via AJAX, to a specially created controller method which will attempt to validate data and output an AJAX response ("" for validation has passed and errors for errors in validation). Then, the result is checked in the jQuery function and the default form behaviour is triggered only if the validation has passed. Otherwise, display the errors and return false; to prevent default submission.

How can I prevent IE Caching from causing duplicate Ajax requests?

We are using the Dynamic Script Tag with JsonP mechanism to achieve cross-domain Ajax calls. The front end widget is very simple. It just calls a search web service, passing search criteria supplied by the user and receiving and dynamically rendering the results.
Note - For those that aren’t familiar with the Dynamic Script Tag with JsonP method of performing Ajax-like requests to a service that return Json formatted data, I can explain how to utilise it if you think it could be relevant to the problem.
The service is WCF hosted on IIS. It is Restful so the first thing we do when the user clicks search is to generate a Url containing the criteria. It looks like this...
https://.../service.svc?criteria=john+smith
We then use a dynamically created Html Script Tag with the source attribute set to the above Url to make the request to our service. The result is returned and we process it to show the results.
This all works fine, but we noticed that when using IE the service receives the request from the client Twice. I used Fiddler to monitor the traffic leaving the browser and sure enough I see two requests with the following urls...
Request 1: https://.../service.svc?criteria=john+smith
Request 2: https://.../service.svc?criteria=john+smith&_=123456789
The second request has been appended with some kind of Id. This Id is different for every request.
My immediate thought is it was something to do with caching. Adding a random number to the end of the url is one of the classic approaches to disabling browser caching. To prove this I adjusted the cache settings in IE.
I set “Check for newer versions of stored pages” to “Never” – This resulted in only one request being made every time. The one with the random number on the end.
I set this setting value back to the default of “Automatic” and the requests immediately began to be sent twice again.
Interestingly I don’t receive both requests on the client. I found this reference where someone is suggesting this could be a bug with IE. The fact that this doesn’t happen for me on Firefox supports this theory.
Can anyone confirm if this is a bug with IE? It could be by design.
Does anyone know of a way I can stop it happening?
Some of the more vague searches that my users will run take up enough processing resource to make doubling up anything a very bad idea. I really want to avoid this if at all possible :-)
I just wrote an article on how to avoid caching of ajax requests :-)
It basically involves adding the no cache headers to any ajax request that comes in
public abstract class MyWebApplication : HttpApplication
{
protected MyWebApplication()
{
this.BeginRequest += new EventHandler(MyWebApplication_BeginRequest);
}
void MyWebApplication_BeginRequest(object sender, EventArgs e)
{
string requestedWith = this.Request.Headers["x-requested-with"];
if (!string.IsNullOrEmpty(requestedWith) && requestedWith.Equals(”XMLHttpRequest”, StringComparison.InvariantCultureIgnoreCase))
{
this.Response.Expires = 0;
this.Response.ExpiresAbsolute = DateTime.Now.AddDays(-1);
this.Response.AddHeader(”pragma”, “no-cache”);
this.Response.AddHeader(”cache-control”, “private”);
this.Response.CacheControl = “no-cache”;
}
}
}
I eventually established the reason for the duplicate requests. As I said, the mechanism I chose to use for making Ajax calls was with Dynamic Script Tags. I build the request Url, created a new Script element and assigned the Url to the src property...
var script = document.createElement(“script”);
script.src = https://....”;
Then to execute the script by appending it to the Document Head. Crucially, I was using the JQuery append function...
$(“head”).append(script);
Inside the append function JQuery was anticipating that I was trying to make an Ajax call. If the type of element being appended is a Script, then it executes a special routine that makes an Ajax request using the XmlHttpRequest object. But the script was still being appended to the document head, and being executed there by the browser too. Hence the double request.
The first came direct from the script – the one I intended to happen.
The second came from inside the JQuery append function. This was the request suffixed with the randomly generated query string argument in the form “&_=123456789”.
I simplified things by preventing the JQuery library side effect. I used the native append function...
document.getElementByTagName(“head”).appendChild(script);
One request now happens in the way I intended. I had no idea that the JQuery append function could have such a significant side effect built in.
See www.enhanceie.com/redir/?id=httpperf for further discussion.

Resources