Cant download PDF with Ajax response (headers are ignored) - ajax

Im trying to download a pdf with ajax request yet the response from that request ignores my "Content-Type:application/pdf" header.
The ajax request
return Superagent.post(url, data).use(this._addDefaults.bind(this));
The symfony response
return new BinaryFileResponse($target);
Workaround
open in new tab and put a direct url for the file.

I think this is similar to a problem I've encountered in the past. Issue is that browsers don't open responses to POST ajax requests by default. I ended up resorting to the automatic form posting instead. In the HTML:
<form method="post" action="http://handler1.ashx" target="_blank">
<input type="hidden" id="data" name="data" value="post_body_stuff"/>
<button id="pdfsubmit" type="submit" value="Submit">Export to PDF</button>
</form>
You can use javascript to put all the data you want to POST as the value on the hidden input field instead of post_body_stuff. This way, when the content comes back the browser will try to open or save it as a file rather than read it as response text.

Related

Export Excel with Laravel, VueJS and Inertiajs

I'm trying to build and application on Laravel, VueJS and inertiajs.
I'm using maatwebsite/excel to export my data into excel format.
I've a vue component which has a normal HTML form
home.vue
<form action="/project-profile" target="_blank" method="POST" enctype="multipart/form-data">
<input type="hidden" name="_token" :value="csrf.content" />
<input type="hidden" name="slug" :value="JSON.stringify(generalDetails.slug)" />
<button class="font-medium tracking-wide">Download Profile</button>
</form>
And on mounted method I'm just placing my csrf token.
mounted() {
this.csrf = document.head.querySelector('meta[name="csrf-token"]');
}
In Laravel part I made a route in web.php file
Route::post('project-profile','ProjectProfileExportController#ProjectProfile');
Whenever I try to export or submit the form, I get page expired error, I followed few guide and it says there is issue with csrf_token but while inspecting the form I can see token is placed appropriately.
I tried doing the same by making this as api, api.php:
Route::post('project-profile', 'ProjectProfileExportController#ProjectProfile');
But this thing also not work as expected.
Screenshot of page expired screen
Screenshot of inspect form element
Any better approach is welcome. Thanks.
Creator of Inertia.js here.
So, we recommend not manually sending the csrf token on each request like this.
A better approach is to use the CSRF functionality already built into axios for this. Axios is the HTTP library that Inertia uses under the hood.
Axios automatically checks for the existence of an XSRF-TOKEN cookie. If it's present, it will then include the token in an X-XSRF-TOKEN header for any requests it makes.
The easiest way to implement this is using server-side middleware. Simply include the XSRF-TOKEN cookie on each response, and then verify the token using the X-XSRF-TOKEN header sent in the requests from axios.
Some frameworks, such as Laravel, do this automatically, meaning there is no configuration required. So, I'd recommend removing the csrf-token meta tag from your template, and removing the _token from your requests. That should take care of your issues.
That all said, keep in mind that you will not be able to download an Excel file from an Inertia request. All Inertia requests MUST return a valid Inertia response. You can use window.open for this. Something like this:
window.open(`/url/to/excel/download?slug=${generalDetails.}`, '_blank')

Is CSRF a threat if not using cookies?

My Flask app is AJAX-heavy, but does not use any cookies. Is CSRF still a threat or is it safe to deploy the app as of now?
I have already looked at this SO question but my situation is slightly different, since I do not have to worry about user's credentials.
I tried an AJAX call from Chrome DevTools (using $.ajax()) to my server which was running on localhost (Flask development server) and I got an error saying
XMLHttpRequest cannot load http://localhost:5000/_ajax. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'chrome://newtab' is therefore not allowed access.
Does this mean I am safe, or is it possible that a hacker could circumvent this and still make AJAX calls to my server?
CSRF isn't just protection against CORS AJAX. I could make a form on my site, and set the action to http://yoursite.com/account/delete. If a user submits my form, without CSRF on your site, the action would succeed. Or if you have things change on GET requests (shouldn't do that anyway), I could add this to my site:
<img src="http://yoursite.com/account/delete" />
and the action would happen when my page loads.
Check out Flask-WTF or this snippet: http://flask.pocoo.org/snippets/3/
EDIT
From your comment:
Change the action of that page to a POST, and have it be accessed through a form instead of a link. If your link was:
<a href="{{ url_for('my_page') }}">Click Here</>
Your form could be (using Flask-WTF, which you would need):
<form action="{{ url_for('my_page') }}" method="POST">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
<input type="submit" value="Click Here" />
</form>

Wordpress AJAX request returning extra HTML tags

I am using Knews plugin for subscribing to my website. Everything is working except IE8: in IE 8 error or success message is not showing. I think since this is an AJAXed form I am getting an AJAX response with some unnecessary HTML tags.
Please see the screenshot. I provide this in the backend:
<span class="error_subscription">Please check e-mail Address</span>
But I am getting the response as on the screenshot:
<span class="error_subscription">Please check e-mail Address</span></p></div>

how to send file data using Dajaxice?

I am using ajax for my website. I have successfully used jQuery.ajax() to asynchronously upload file to server. I am using Dajax and Dajaxice therefore I plan to use these application for file upload as well. I tried this example. It is working fine. But if I add file field into my html form, it does not send file to server. My html form looks like
<form id="myform" action="/file/" method="post" enctype="multipart/form-data">
<div style='display:none'><input type='hidden' name='csrfmiddlewaretoken' value='AaSmyBEwQLSD3YghRAD9Cf2uxEjzESUe' /></div>
<p><label for="id_docfile">Select a file</label> max. 42 megabytes</p>
<p><input type="file" name="docfile" id="id_docfile" /></p>
<p><input type="submit" value="Upload" /></p>
</form>
This question has been asked at many place but never answered.
Afaik there is currently no provision within dajax / dajaxice to upload files.
I have used dajax in a few projects and have got round this by using blueimp/jquery-file-upload and a django view that accepts a POST of the upload file and return a JSON string to the client.
This is a less than perfect solution not least because the jquery-file-upload button is styled differently from normal html form elements, it is possible to style the whole form using jQuery-ui, although this is a lot of additional work.
Both, dwr which is pretty much dajax for Java, and tasty pie for django do offer file uploading, so in theory it should be possible to implement it.
I'm happy to post a sample of my ajax solution if anyone would find them useful.
I've also faced this problem recently. So, I've digged a little and discovered some answers.
It is working fine. But if I add file field into my html form, it does not send file to server.
There's serialize() method used in the doc example. But according to the jQuery doc:
Data from file select elements is not serialized.
Also, there's no clear way to get ajax file upload, because JS doesn't have access to the outside of the client browser. So, I don't think it's possible to make using dajaxice.
The easiest hack, I've found is to post form to the invisible iframe using target option:
<form method='POST' action='/upload' enctype='multipart/form-data' target='submit-iframe'>
so, only the iframe will be refreshed. Using js you than can get data from it catching the load() event.
More detailed process described here

AJAX call fails depending on position in code, browser fires document.ready mid-call. Twitter Bootstrap issue?

I am chasing a nasty issue. An AJAX call in an onclick handler does not complete, as the browser fires document.ready mid-call. When tracing the readystate and status in the Firebug console I get:
READYSTATECHANGE:1 STATUS:0
READYSTATECHANGE:2 STATUS:0
READYSTATECHANGE:4 STATUS:0
Document Ready (-> this is the
second firing, breaking everything as the UI is rewired )
I believe I am not facing a cross-domain security block as the same AJAX call will complete correctly when called elsewhere in the page.
I am using Jquery 1.8.1 and I have tried multiple variations of AJAX client calls (i.e.
$.getJSON
$.ajax
as well as using the standard XMLHttpRequest object.
Has anyone seen this before? Pointers for deeper debugging would be fantastic.
After having debugged the issues I now have a work around. My AJAX call was invoked from a click handler linked to a Twitter Bootstrap Button. Clicking the button triggered the AJAX call but also a window.load event, which refreshed the JS application.
My work around was to replace the <button>..</button> with an <input>..</input> field, see below:
<form class="form-search">
<label>Enter search string:
<input id="SearchString" type="text" class="input-medium search-query">
<!-- Broken: <button id="SearchAction" type="submit" class="btn btn-primary"> Search </button> -->
<!-- This works: -->
<input type="button" id="SearchAction" value="Go Find"/>
<img id="RssAction" style="vertical-align:bottom" src="images/feed-icon-14x14.png">
</label>
</form>
This may not be the root cause yet.

Resources