Skip to content

Commit

Permalink
Download hack for Slack
Browse files Browse the repository at this point in the history
  • Loading branch information
viktor44 committed Feb 11, 2024
1 parent 94eb992 commit 817ed93
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 46 deletions.
130 changes: 88 additions & 42 deletions app/services/services/tab-webcontents/api.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { BrowserWindow, session, webContents } from 'electron';
import { BrowserWindow, DidCreateWindowDetails, webContents } from 'electron';
import { fromEvent, merge } from 'rxjs';
import { filter, take } from 'rxjs/operators';
import { RPC } from '../../lib/types';
Expand Down Expand Up @@ -121,46 +121,92 @@ export const addOnNotificationCloseObserver = (wc: Electron.WebContents, obs: RP
return () => { };
};

/**
* Gmail has a weird way to open PDF for printing.
* They are opened with a `about:blank` or `about:blank#blocked` url, then code is injected into the new tab/window,
* which is then redirected to a new URL which will trigger the print.
*
* What we are doing to handle this case:
* - Create a new hidden BrowserWindow and attach is to `event.newGuest`
* - Wait for this window to trigger a download
* - If within 2 seconds we received a download, we close the window
* - Else, we show it or dispatch it
*
* NB: When overriding the User Agent to bypass Google blacklist, ALL URLs seems to be handled that way instead of just downloads...
*
* NB: As the print PDF thingy is tied to the PDF viewer which doesn't really work in Electron yet,
* we receive a download event instead of a print event.
*/
export const handleHackGoogleAppsURLs =
async (event: Event, options: Partial<Electron.BrowserWindowConstructorOptions>): Promise<BrowserWindow | undefined> => {
const actualOptions: Electron.BrowserWindowConstructorOptions = {
...options,
width: 400,
height: 400,
show: false,
};
const guest = new BrowserWindow(actualOptions);
(event as any).newGuest = guest;

// Wait 2 seconds to receive a downloadItem
const downloadItem = await Promise.race([
new Promise<boolean>(resolve => {
session.defaultSession!.once('will-download', () => resolve(true));
}),
new Promise<void>(resolve => { setTimeout(resolve, 2000); }),
]);

// If download event received, we close the webcontents
if (downloadItem) {
guest.close();
return;
// /**
// * Gmail has a weird way to open PDF for printing.
// * They are opened with a `about:blank` or `about:blank#blocked` url, then code is injected into the new tab/window,
// * which is then redirected to a new URL which will trigger the print.
// *
// * What we are doing to handle this case:
// * - Create a new hidden BrowserWindow and attach is to `event.newGuest`
// * - Wait for this window to trigger a download
// * - If within 2 seconds we received a download, we close the window
// * - Else, we show it or dispatch it
// *
// * NB: When overriding the User Agent to bypass Google blacklist, ALL URLs seems to be handled that way instead of just downloads...
// *
// * NB: As the print PDF thingy is tied to the PDF viewer which doesn't really work in Electron yet,
// * we receive a download event instead of a print event.
// */
// export const handleHackGoogleAppsURLs =
// async (event: Event, options: Partial<Electron.BrowserWindowConstructorOptions>): Promise<BrowserWindow | undefined> => {
// const actualOptions: Electron.BrowserWindowConstructorOptions = {
// ...options,
// width: 400,
// height: 400,
// show: false,
// };
// const guest = new BrowserWindow(actualOptions);
// (event as any).newGuest = guest;

// // Wait 2 seconds to receive a downloadItem
// const downloadItem = await Promise.race([
// new Promise<boolean>(resolve => {
// session.defaultSession!.once('will-download', () => resolve(true));
// }),
// new Promise<void>(resolve => { setTimeout(resolve, 2000); }),
// ]);

// // If download event received, we close the webcontents
// if (downloadItem) {
// guest.close();
// return;
// }

// return guest;
// };

const downloadHackPerfixes: string[] = [
'https://files.slack.com', // Download file from Slack.com
'about:blank', //
];

const getDownloadHackPrefix = (url : string): (string | null) => {
for (const prefix of downloadHackPerfixes) {
if (url.startsWith(prefix)) {
return prefix;
}
}
return null;
}

return guest;
};
export const handleDownloadHack = (wc: Electron.WebContents, url: string): boolean => {
let result: boolean = false;
const downloadUrlPrefix = getDownloadHackPrefix(url);
if (downloadUrlPrefix !== null) {
result = true;
wc.once('did-create-window', (window: BrowserWindow, details: DidCreateWindowDetails) => {
if (getDownloadHackPrefix(details.url) !== downloadUrlPrefix) {
return;
}
// Wait 2 seconds to receive a downloadItem
Promise.race([
new Promise<boolean>(resolve => {
wc.session.once('will-download', () => resolve(true));
}),
new Promise<boolean>(resolve => {
setTimeout(() => resolve(false), 2000)
}),
])
.then(downloadItem => {
if (downloadItem) {
window.close();
}
else if (window.webContents.getURL().startsWith(downloadUrlPrefix)) {
// if popup is still the same after 2 seconds, we show it to let it finish
window.show();
}
});
});
}
return result;
}
12 changes: 9 additions & 3 deletions app/services/services/tab-webcontents/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
addOnPreventUnload,
awaitDomReady,
getWebContentsFromIdOrThrow,
handleHackGoogleAppsURLs,
handleDownloadHack,
} from './api';
import {
AlertDialogProviderService,
Expand Down Expand Up @@ -266,10 +266,12 @@ export class TabWebContentsServiceImpl extends TabWebContentsService implements

async setUrlDispatcherProvider(provider: RPC.Node<UrlDispatcherProviderService>) {
return new ServiceSubscription(this.onNewWebviews().subscribe(wc => {

wc.setWindowOpenHandler((details: HandlerDetails) => {

log.debug('WindowOpen', details, process.type);
// log.debug('WindowOpen', details, process.type);

let useDownloadHack = false;

if (details.disposition === 'new-window') {
if (this.isNewWindowForUserRequest(details)) {
Expand All @@ -282,6 +284,9 @@ export class TabWebContentsServiceImpl extends TabWebContentsService implements
provider.dispatchUrl(details.url, wc.id, DEFAULT_BROWSER);
return { action: 'deny' };
}
else if (details.disposition === 'foreground-tab') {
useDownloadHack = handleDownloadHack(wc, details.url);
}

//vk: 2023.09.29 don't know how to verify this hack
// will fix it later
Expand Down Expand Up @@ -309,6 +314,7 @@ export class TabWebContentsServiceImpl extends TabWebContentsService implements
action: 'allow',
overrideBrowserWindowOptions: {
fullscreen: false,
show: !useDownloadHack,
}
};
});
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "station-desktop-app",
"private": true,
"productName": "Station",
"version": "2.7.0-b2",
"version": "2.8.0-b1",
"description": "Station",
"homepage": "https://getstation.com",
"author": {
Expand Down

0 comments on commit 817ed93

Please sign in to comment.