diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a4270ec..b9ba51b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,8 @@ Release date: TBD #### All Platforms - Fixed an issue where an unexpected row appeared after switching channels with `CTRL+K` shortcut. [#426](https://github.com/mattermost/desktop/issues/426) +- Fixed an issue where an unexpected extra window opened when clicking the public link for an uploaded file. + [#390](https://github.com/mattermost/desktop/issues/390) #### Windows - Fixed an issue where the main window still has focus and exists diff --git a/src/browser/components/MattermostView.jsx b/src/browser/components/MattermostView.jsx index 667ac6d3..76bcab18 100644 --- a/src/browser/components/MattermostView.jsx +++ b/src/browser/components/MattermostView.jsx @@ -66,9 +66,14 @@ const MattermostView = React.createClass({ ipcRenderer.send('confirm-protocol', destURL.protocol, e.url); return; } + if (currentURL.host === destURL.host) { - // New window should disable nodeIntergration. - window.open(e.url, 'Mattermost', 'nodeIntegration=no, show=yes'); + if (destURL.path.match(/^\/api\/v[3-4]\/public\/files\//)) { + ipcRenderer.send('download-url', e.url); + } else { + // New window should disable nodeIntergration. + window.open(e.url, 'Mattermost', 'nodeIntegration=no, show=yes'); + } } else { // if the link is external, use default browser. shell.openExternal(e.url); diff --git a/src/main.js b/src/main.js index 8defdd14..90a0da1c 100644 --- a/src/main.js +++ b/src/main.js @@ -61,6 +61,7 @@ var certificateStore = require('./main/certificateStore').load(path.resolve(app. const {createMainWindow} = require('./main/mainWindow'); const appMenu = require('./main/menus/app'); const trayMenu = require('./main/menus/tray'); +const downloadURL = require('./main/downloadURL'); const allowProtocolDialog = require('./main/allowProtocolDialog'); const SpellChecker = require('./main/SpellChecker'); @@ -327,6 +328,18 @@ app.on('login', (event, webContents, request, authInfo, callback) => { allowProtocolDialog.init(mainWindow); +ipcMain.on('download-url', (event, URL) => { + downloadURL(mainWindow, URL, (err) => { + if (err) { + dialog.showMessageBox(mainWindow, { + type: 'error', + message: err.toString() + }); + console.log(err); + } + }); +}); + // This method will be called when Electron has finished // initialization and is ready to create browser windows. app.on('ready', () => { diff --git a/src/main/downloadURL.js b/src/main/downloadURL.js new file mode 100644 index 00000000..0d1187f2 --- /dev/null +++ b/src/main/downloadURL.js @@ -0,0 +1,52 @@ +const fs = require('fs'); +const path = require('path'); +const zlib = require('zlib'); +const electron = require('electron'); +const {app, dialog} = electron; + +function downloadURL(browserWindow, URL, callback) { + const {net} = electron; + const request = net.request(URL); + request.setHeader('Accept-Encoding', 'gzip,deflate'); + request.on('response', (response) => { + const file = getAttachmentName(response.headers); + const dialogOptions = { + defaultPath: path.join(app.getPath('downloads'), file) + }; + dialog.showSaveDialog(browserWindow, dialogOptions, (filename) => { + if (filename) { + saveResponseBody(response, filename, callback); + } + }); + }).on('error', callback); + request.end(); +} + +function getAttachmentName(headers) { + if (headers['content-disposition']) { + const contentDisposition = headers['content-disposition'][0]; + const matched = contentDisposition.match(/filename="(.*)"/); + if (matched) { + return path.basename(matched[1]); + } + } + return ''; +} + +function saveResponseBody(response, filename, callback) { + const output = fs.createWriteStream(filename); + output.on('close', callback); + switch (response.headers['content-encoding']) { + case 'gzip': + response.pipe(zlib.createGunzip()).pipe(output).on('error', callback); + break; + case 'deflate': + response.pipe(zlib.createInflate()).pipe(output).on('error', callback); + break; + default: + response.pipe(output).on('error', callback); + break; + } +} + +module.exports = downloadURL;