Download S3 file from pre-signed URL without popup blocker - javascript

I have a Meteor application where I'm downloading files from S3 using pre-signed URLs (need to be generated with an API call).
I was having an issue with popup blockers preventing a new tab from opening with the url generated by the AWS-SDK so I changed my code to the following:
downloadDocument(document, event) {
// open tab immediately to prevent popup blocker
const myNewTab = window.open();
// call method to generate url
Meteor.call('Events.Methods.Document.Download', { key: document.key, eventId: event._id }, (error, res) => {
if (error) { ... } // removed handle error code
// if url generated, set tab location to url
if (res) myNewTab.location.href = res;
// auto close the tab after 1 second
myNewTab.setTimeout(() => { myNewTab.close(); }, 1000);
});
}
This code is working for the most part but it doesn't feel very clean. Also if the API call ever takes more than 1 second (slow internet) then the tab will close before the download begins
How can I change this so that I can wait for the download to happen, before closing the tab? Or a similar solution that would result in me ensuring the downloads always go through without popup blockers being an issue?
Thanks

You are always going to run afoul of pop-up blockers if you open a new window.
What you should do is generate an <a href="my-custom-server-generated-url" download> link with the download property, which will force a download without needing a new window.
Then you also don't need to close the window on a timer (which wasn't a good approach in the first place)

This was happening only in Safari, so we switched to always downloading the file instead of opening in a new window in Safari/mobile.

Related

Is there a way to detect if the browser has a mailto protocol handler set?

I have a site that dynamically builds a mailto url which it then opens in a new tab/window, using window.open().
window.open("mailto:" + encodeURIComponent(r["to"]));
I'm testing in Chrome at this stage, so other browsers may act differently.
If Chrome has a mailto protocol handler set up (e.g. GMail), then it works as expected.
If Chrome does not have a mailto protocol handler set up, it just opens a tab with the mailto url and nothing else.
That's not the worst result, but it would be nice if there was a way of knowing in advance, so that the user could be in some way guided to setting up their browser so that the mailto url worked nicely.
Previously, I was just opening in the same page by setting window.location.href to the url:
windows.location.href = "mailto:" + encodeURIComponent(r["to"]);
This wasn't great because if there was no protocol handler set, nothing happened. I also would consider this as an option, IF I can at least detect the situation, but wasn't able to find any indication of that either. I guess one option would be to set a timer which if it reached execution could alert the user?
Anyone else already solved this? Seems like a pretty common requirement.
Thanks
Here's what I ended up working with. It doesn't work in all cases, but provides at least some help in recognising unhandled protocols.
It attempts to open the URL in a new window and then after 2s it takes a look to see if it can read the location. If it has opened a third party site (e.g. GMail) this will raise and exception - so we treat this as success.
If no exception occurs, this returns "about:blank" which means we (probably) failed.
function openWin(url) {
return new Promise((resolve, reject) => {
const w = window.open(url);
if (!w) {
reject();
}
setTimeout(function() {
try {
const working = w.document.location.href;
} catch (e) {
resolve();
return;
}
w.close();
reject();
}, 2000);
});
}
Called with something like this:
openWin('mailto:' + encodeURIComponent(to)).then(() => {
// handle success
}).catch(() => {
// handle failure
});
Caveat: This only works for web-based protocol handlers. If for example your mailto is handled by an email app, then this will fail.
In my case, most people would be using web-based email, so it works for most cases. On failure I show a message to the affect of "If your email didn't open, copy the email address here..."

Disable tabs opened in selenium (Node.js)

Im using the selenium webdriver for node.js and im also loading an extension, loading the extension works fine but when I start my project it goes to the page I want then instantly the extension opens a new tab (Thank you for adding this extension bla bla bla), Im wondering if theres a way to disable tabs that are not opened by myself, ive tried this:
await driver.get('https://mywebsite.com') //open my initial site
await driver.sleep(1000) //give time for the extension site to open
driver.switchTo(await driver.getAllWindowHandles()[1]) //switch to extension site
await driver.close()
driver.switchTo(await driver.getAllWindowHandles()[0]) //switch back to the main site
//rest of my code
Unfortunately this just does not seem to work, any advice appreciated!
There's no way to disable tabs not opened by your script. As long as you don't change window handles, the driver will still be on the original tab. You can proceed with the script from there, ignoring the other opened tabs.
I think the main issue I see with your code is that you are passing parameters to .switchTo() instead of .window(). It should be driver.switchTo().window(handle);.
If you want to find the new window to close it, I wrote that code in this answer. All you need to do is to add the .close() line after that code and switch back to the original handle, which you already have in your current code (after fixing with my feedback above).
Another approach is heavily based on the selenium.dev docs:
// Open the initial site
await driver.get('https://mywebsite.com')
// Store the ID of the original window
const originalWindow = await driver.getWindowHandle();
// Wait for the new window or tab
await driver.wait(async () => (await driver.getAllWindowHandles()).length === 2, 10000);
// Loop through until we find a new window handle
const windows = await driver.getAllWindowHandles();
windows.forEach(async handle => {
if (handle !== originalWindow) {
await driver.switchTo().window(handle);
}
});
await driver.close()
await driver.switchTo().window(originalWindow);
// Rest of the code

How to print pdf from server after button click in Angular 2+

On my page I have button that should download concrete pdf file from backend and open the printing window. I tried answers here that included some blob stuff. It did not work. Tried to change route and embed the file in the HTML and after files would be downloaded to call window.print() on the page, but page was blank. Tried also printJS, but wasn't able to make it work, since it kept showing printJS is not a part of onclick function or something like that. Any advice would be helpful.
The only solution I came up with was to do it like this:
printPdf(){
this.network.getPdfHash()
.pipe(take(1))
.subscribe((res) => {
//res === url to the location of the PDF
let win = window.open(res, "_blank");
win.focus();
win.addEventListener(
"load",
() => {
setTimeout(() => {
//to give time for the browser to load the pdf
win.window.print();
}, 250);
},
true
);
});
}

Is there a possibility to download text-content from ftp link programmatically?

I'm am on an embedded system which has an implemented webserver and a ftp-server.
Both servers are handled by a RTOS and I cannot change server-side code at the time.
I need to access and download text-files programmatically over the ftp-server from my website.
So far I am dynamically creating an ftp-link and open it inside a new window, which only shows me the text-content of the requested file.
Now I want to download this text content for serveral files I am about to open in a loop:
Open window - download textcontent - Close window
... Open Window ... and so on.
I cannot "inject" Javascript for the new window, to make it download it content if Im right?
I open the window with
window.open('ftp://username:passwort#myfilename.txt')
from a script running on my webpage.
Is there any possibility to access and download that text content as described?
At the time I do not have the possibility to access the textfiles other than ftp, since the webserver and ftpserver are not on the same filesystem and I can not change the code on the serverside.
Now I know this is kind of hacky... yet I need a workaround for now to access the textfiles.
Thank you in advance!
If you're using node you can try node-ftp
Here's a quick example of how to use:
var Client = require('ftp');
var c = new Client();
c.on('ready', function() {
c.get('foo.txt', function(err, stream) {
if (err) throw err;
console.log(stream);
stream.once('close', function() { c.end(); });
});
});
// connect to localhost:21 as anonymous
c.connect();

Get URL of popup window opened from a Chrome Extension

I've got a Chrome extension that creates a popup window that the user needs to use for a login system. You click on the extension icon and it opens up its application (AngularJS in my case). The user then clicks on a button which calls chrome.windows.create() to open a popup.
I would like the main extension app to monitor the URL of that popup for changes.
I create the popup from the extension this way:
chrome.windows.create(
{
url: 'https://some.external.url.com/whatever',
type: 'panel',
width: 600,
height: 600
},
function (windowReference) {
console.log('My Window:', windowReference);
// start monitoring URL of windowReference somehow
// could be as simple as a setInterval() loop
}
)
The problem is that the windowReference object passed to the callback doesn't have the current URL of the popup. Since the user can interact with the page in the popup (I'm pointing it at out OAuth2 system), the URL will change at times. I want to see that - either actively as changes are made, or by simply querying the current URL periodically.
This is what the windowReference object contains:
{
alwaysOnTop:false,
focused:false,
height:600,
id:1089,
incognito:false,
left:61,
state:"normal",
top:23,
type:"popup",
width:600
}
You can see that there is an ID there, and that, to me, suggest that I might be able to use it to call some other method to get the real URL information I'm after.
Any help would be appreciated.
So the answer turns out to be pretty simple. As Rob W mentioned in a comment, you use the chrome.tabs.query() method to do the search as you would for any other tab.
The missing part for me was that you can use the id from the window reference you get when the popup is created to get the desired results from the tabs query:
chrome.tabs.query(
{ windowId: windowReference.id },
function callback(tabs) {
var popup = tabs[0];
$log.debug("Popup URL:", popup.url);
}
);
You can see that I passed the ID as the value of the windowId parameter in the search query object.

Categories