diff --git a/src/browser/components/MattermostView.jsx b/src/browser/components/MattermostView.jsx index f5173d8f..cc1f3afd 100644 --- a/src/browser/components/MattermostView.jsx +++ b/src/browser/components/MattermostView.jsx @@ -97,6 +97,8 @@ export default class MattermostView extends React.Component { } else if (Utils.isTeamUrl(this.props.src, e.url, true) || Utils.isPluginUrl(this.props.src, e.url)) { // New window should disable nodeIntegration. window.open(e.url, remote.app.name, 'nodeIntegration=no, contextIsolation=yes, show=yes'); + } else if (Utils.isManagedResource(this.props.src, e.url)) { + e.preventDefault(); } else { e.preventDefault(); shell.openExternal(e.url); diff --git a/src/common/config/buildConfig.js b/src/common/config/buildConfig.js index a92e915e..bf4b0a65 100644 --- a/src/common/config/buildConfig.js +++ b/src/common/config/buildConfig.js @@ -15,6 +15,7 @@ * @prop {boolean} enableServerManagement - Whether users can edit servers configuration. * Specify at least one server for "defaultTeams" * when "enableServerManagement is set to false + * @prop {[]} managedResources - Defines which paths are managed */ const buildConfig = { defaultTeams: [/* @@ -26,6 +27,7 @@ const buildConfig = { helpLink: 'https://about.mattermost.com/default-desktop-app-documentation/', enableServerManagement: true, enableAutoUpdater: true, + managedResources: ['trusted'], }; export default buildConfig; diff --git a/src/main.js b/src/main.js index 623b82c5..1d58ab8d 100644 --- a/src/main.js +++ b/src/main.js @@ -540,12 +540,13 @@ function handleAppWebContentsCreated(dc, contents) { log.info(`Popup window already open at provided url: ${url}`); return; } - if (Utils.isPluginUrl(server.url, parsedURL)) { + if (Utils.isPluginUrl(server.url, parsedURL) || Utils.isManagedResource(server.url, parsedURL)) { if (!popupWindow || popupWindow.closed) { popupWindow = new BrowserWindow({ backgroundColor: '#fff', // prevents blurry text: https://electronjs.org/docs/faq#the-font-looks-blurry-what-is-this-and-what-can-i-do parent: mainWindow, show: false, + center: true, webPreferences: { nodeIntegration: false, contextIsolation: true, @@ -559,11 +560,15 @@ function handleAppWebContentsCreated(dc, contents) { }); } - // currently changing the userAgent for popup windows to allow plugins to go through google's oAuth - // should be removed once a proper oAuth2 implementation is setup. - popupWindow.loadURL(url, { - userAgent: popupUserAgent[process.platform], - }); + if (Utils.isManagedResource(server.url, parsedURL)) { + popupWindow.loadURL(url); + } else { + // currently changing the userAgent for popup windows to allow plugins to go through google's oAuth + // should be removed once a proper oAuth2 implementation is setup. + popupWindow.loadURL(url, { + userAgent: popupUserAgent[process.platform], + }); + } } }); @@ -817,7 +822,6 @@ function initializeAfterAppReady() { return; } - // get the requesting webContents url const requestingURL = webContents.getURL(); // is the requesting url trusted? diff --git a/src/utils/util.js b/src/utils/util.js index 44facb59..b34aa35a 100644 --- a/src/utils/util.js +++ b/src/utils/util.js @@ -7,6 +7,8 @@ import electron, {remote} from 'electron'; import log from 'electron-log'; import {isUri, isHttpUri, isHttpsUri} from 'valid-url'; +import buildConfig from '../common/config/buildConfig'; + function getDomain(inputURL) { const parsedURL = url.parse(inputURL); return `${parsedURL.protocol}//${parsedURL.host}`; @@ -69,6 +71,14 @@ function getServerInfo(serverUrl) { return {origin: parsedServer.origin, subpath, url: parsedServer}; } +function getManagedResources() { + if (!buildConfig) { + return []; + } + + return buildConfig.managedResources || []; +} + function isTeamUrl(serverUrl, inputUrl, withApi) { const parsedURL = parseURL(inputUrl); const server = getServerInfo(serverUrl); @@ -76,7 +86,20 @@ function isTeamUrl(serverUrl, inputUrl, withApi) { return null; } - const nonTeamUrlPaths = ['plugins', 'signup', 'login', 'admin', 'channel', 'post', 'oauth', 'admin_console']; + // pre process nonTeamUrlPaths + let nonTeamUrlPaths = [ + 'plugins', + 'signup', + 'login', + 'admin', + 'channel', + 'post', + 'oauth', + 'admin_console', + ]; + const managedResources = getManagedResources(); + nonTeamUrlPaths = nonTeamUrlPaths.concat(managedResources); + if (withApi) { nonTeamUrlPaths.push('api'); } @@ -97,6 +120,20 @@ function isPluginUrl(serverUrl, inputURL) { parsedURL.pathname.toLowerCase().startsWith('/plugins/'))); } +function isManagedResource(serverUrl, inputURL) { + const server = getServerInfo(serverUrl); + const parsedURL = parseURL(inputURL); + if (!parsedURL || !server) { + return false; + } + + const managedResources = getManagedResources(); + + return ( + equalUrlsIgnoringSubpath(server, parsedURL) && managedResources && managedResources.length && + managedResources.some((managedResource) => (parsedURL.pathname.toLowerCase().startsWith(`${server.subpath}${managedResource}/`) || parsedURL.pathname.toLowerCase().startsWith(`/${managedResource}/`)))); +} + function getServer(inputURL, teams) { const parsedURL = parseURL(inputURL); if (!parsedURL) { @@ -189,6 +226,7 @@ export default { getServerInfo, isTeamUrl, isPluginUrl, + isManagedResource, getDisplayBoundaries, dispatchNotification, getHost,