0

I need to create a small browser-based application that helps users download/save, and possibly print to the default printer, a large number of files from a webserver we have no control over (but we have all the URIs beforehand).

These files are hidden behind a "single sign-on" (SSO) that can only be performed via a browser and requires a user. Hence, it must be a browser-based solution, where we piggyback on to the session established by the SSO.

The users' platform is Windows 7.

The point is to save the users from going through a lot of clicks per file (download, where to save, etc.) when they need to perform this operation (daily).

At this point all the files are PDF, but that might change in the future.

A browser-agnostic solution is preferred (and I assume more robust when it comes to future browser updates).

But we can base it on a particular browser if needed.

How would you do this from Javascript?

AmerllicA
  • 29,059
  • 15
  • 130
  • 154
herira
  • 149
  • 3
  • 11
  • Did you try to use a download manager extension for the web browser? – Philipp Jan 15 '14 at 09:51
  • I don't think this is allowed by the browser security model. Scripts can't create files without the user knowing it. – Barmar Jan 15 '14 at 09:51
  • 2
    you cannot force a download or a print task without user interaction. What If I send to your printer the whole Divina Commedia as a joke? – Fabrizio Calderan Jan 15 '14 at 09:52
  • Firefox is the only common browser that easily offers such functionality to add-on developers. (well, if you don't mind that the downloads end up at a pre-defined folder (Downloads), then Chrome is also an option, see [`chrome.downloads`](https://developer.chrome.com/extensions/downloads.html)); Though what you're describing sounds much like "browser automation", there are existing tools for that, such as [Selenium](http://docs.seleniumhq.org/). – Rob W Jan 15 '14 at 09:53
  • _Some_ user interaction is okay (start/accept the proces). The point is to save the user from performing one (or multiple) clicks per file. – herira Jan 15 '14 at 09:54
  • You cannot save files (except with html5 file api) in browser without user intervention. The usual way is file by file as a attachment with Content-Disposition: attachment; But you can write an app that does that. Anything done by the browser can be done by standard programming APIs (java, c, python, event bash script). You need to figure out, how SSO is done. Does it utilize auth cookies, or basic authentication header or some hidden fields. I would suggest to you, to try to get solution with Jmetre (http sampler) and then transfer it to some – Mitja Gustin Jan 15 '14 at 09:54
  • Possible duplicate of: http://stackoverflow.com/questions/11353425/force-a-browser-to-save-file-as-after-clicking-link . If I understand correctly you have the files paths what you can do is force a click with javascript on the link to the file. – Ovidiu Iacomi Jan 15 '14 at 09:57

2 Answers2

0

As the comments to my question says, this isn't really allowed by the browsers for security reasons.

My workaround for now (only tested using IE11) is to manually change the security settings of the users browser, and then download the files as a blob into a javascript variable using AJAX, followed by upload of same blob to my own server again using AJAX.

"My own server" is a Django site created for this purpose, that also knows which files to download for the day, and provide the javascript needed. The user goes to this site to initiate the daily download after performing the SSO in a separate browser tab.

On the server I can then perform whatever operations needed for said files.

Many thanks to this post https://stackoverflow.com/a/13887220/833320 for the handling of binary data in AJAX.

1) In IE, add the involved sites to the "Local Intranet Zone", and enable "Access data sources across domains" for this zone to overcome the CORS protection otherwise preventing this.

Of course, consider the security consequences involved in this...

2) In javascript (browser), download the file as a blob and POST the resulting data to my own server:

var x = new XMLHttpRequest();
x.onload = function() {
    // Create a form
    var fd = new FormData();
    fd.append('csrfmiddlewaretoken', '{{ csrf_token }}'); // Needed by Django
    fd.append('file', x.response); // x.response is a Blob object

    // Upload to your server
    var y = new XMLHttpRequest();
    y.onload = function() {
        alert('File uploaded!');
    };
    y.open('POST', '/django/upload/');
    y.send(fd);
};
x.open('GET', 'https://external.url', true);
x.responseType = 'blob';    // <-- This is necessary!
x.send();

3) Finally (in Django view for '/django/upload/'), receive the uploaded data and save as file - or whatever...

filedata = request.FILES['file'].read()

with open('filename', 'wb') as f:
    f.write(filedata)

Thanks all, for your comments.

And yes, the real solution would be to overcome the SSO (that requieres the user), so it all could be done by the server itself.

But at least I learned a little about getting/posting binary data using modern XMLHttpRequests. :)

Community
  • 1
  • 1
herira
  • 149
  • 3
  • 11
0

Actually, I had a problem like it, I wanted to download a binary file(an image) and store it and then use it when I need it, So I decided to download it with Fetch API Get call:

const imageAddress = 'an-address-to-my-image.jpg'; // sample address

fetch(imageAddress)
  .then(res => res.blob)  // <-- This is necessary!
  .then(blobFileToBase64)
  .then(base64FinalAnswer => console.log(base64FinalAnswer))

The blobFileToBase64 is a helper function that converts blob binary file to a base64 data string:

const blobToBase64 = blob => {
  const reader = new FileReader();
  reader.readAsDataURL(blob);
  return new Promise(resolve => {
    reader.onloadend = () => {
      resolve(reader.result);
    };
  });
};

In the end, I have the base64FinalAnswer and I can do anything with it.

AmerllicA
  • 29,059
  • 15
  • 130
  • 154