[MM-25748]Allow access to managed resources (#1311)

* init of a branch

* Add more descriptive comment

* fix for linter errors

* Refactor of popup code
Remove isTrustedPopupWindow check in setPermissionRequestHandler
Check which UA needs to be sent depending on a url

* Update src/utils/util.js

Co-authored-by: Guillermo Vayá <guivaya@gmail.com>

* Remove commented code:

* Revert package.json and package-lock.json to original ones

* Implement buildConfig support for multiple trusted resources

* Fix for a typo

* add comments

* code cleanup

Co-authored-by: Dusan Panic <dusan@salestrekker.com>
Co-authored-by: dpanic <dpanic@0point.co>
Co-authored-by: Guillermo Vayá <guivaya@gmail.com>
This commit is contained in:
Dušan Panić
2020-06-19 15:32:14 +02:00
committed by GitHub
parent 81522a3b2d
commit a5ce5700cc
4 changed files with 54 additions and 8 deletions

View File

@@ -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)) { } else if (Utils.isTeamUrl(this.props.src, e.url, true) || Utils.isPluginUrl(this.props.src, e.url)) {
// New window should disable nodeIntegration. // New window should disable nodeIntegration.
window.open(e.url, remote.app.name, 'nodeIntegration=no, contextIsolation=yes, show=yes'); 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 { } else {
e.preventDefault(); e.preventDefault();
shell.openExternal(e.url); shell.openExternal(e.url);

View File

@@ -15,6 +15,7 @@
* @prop {boolean} enableServerManagement - Whether users can edit servers configuration. * @prop {boolean} enableServerManagement - Whether users can edit servers configuration.
* Specify at least one server for "defaultTeams" * Specify at least one server for "defaultTeams"
* when "enableServerManagement is set to false * when "enableServerManagement is set to false
* @prop {[]} managedResources - Defines which paths are managed
*/ */
const buildConfig = { const buildConfig = {
defaultTeams: [/* defaultTeams: [/*
@@ -26,6 +27,7 @@ const buildConfig = {
helpLink: 'https://about.mattermost.com/default-desktop-app-documentation/', helpLink: 'https://about.mattermost.com/default-desktop-app-documentation/',
enableServerManagement: true, enableServerManagement: true,
enableAutoUpdater: true, enableAutoUpdater: true,
managedResources: ['trusted'],
}; };
export default buildConfig; export default buildConfig;

View File

@@ -540,12 +540,13 @@ function handleAppWebContentsCreated(dc, contents) {
log.info(`Popup window already open at provided url: ${url}`); log.info(`Popup window already open at provided url: ${url}`);
return; return;
} }
if (Utils.isPluginUrl(server.url, parsedURL)) { if (Utils.isPluginUrl(server.url, parsedURL) || Utils.isManagedResource(server.url, parsedURL)) {
if (!popupWindow || popupWindow.closed) { if (!popupWindow || popupWindow.closed) {
popupWindow = new BrowserWindow({ 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 backgroundColor: '#fff', // prevents blurry text: https://electronjs.org/docs/faq#the-font-looks-blurry-what-is-this-and-what-can-i-do
parent: mainWindow, parent: mainWindow,
show: false, show: false,
center: true,
webPreferences: { webPreferences: {
nodeIntegration: false, nodeIntegration: false,
contextIsolation: true, 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 if (Utils.isManagedResource(server.url, parsedURL)) {
// should be removed once a proper oAuth2 implementation is setup. popupWindow.loadURL(url);
popupWindow.loadURL(url, { } else {
userAgent: popupUserAgent[process.platform], // 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; return;
} }
// get the requesting webContents url
const requestingURL = webContents.getURL(); const requestingURL = webContents.getURL();
// is the requesting url trusted? // is the requesting url trusted?

View File

@@ -7,6 +7,8 @@ import electron, {remote} from 'electron';
import log from 'electron-log'; import log from 'electron-log';
import {isUri, isHttpUri, isHttpsUri} from 'valid-url'; import {isUri, isHttpUri, isHttpsUri} from 'valid-url';
import buildConfig from '../common/config/buildConfig';
function getDomain(inputURL) { function getDomain(inputURL) {
const parsedURL = url.parse(inputURL); const parsedURL = url.parse(inputURL);
return `${parsedURL.protocol}//${parsedURL.host}`; return `${parsedURL.protocol}//${parsedURL.host}`;
@@ -69,6 +71,14 @@ function getServerInfo(serverUrl) {
return {origin: parsedServer.origin, subpath, url: parsedServer}; return {origin: parsedServer.origin, subpath, url: parsedServer};
} }
function getManagedResources() {
if (!buildConfig) {
return [];
}
return buildConfig.managedResources || [];
}
function isTeamUrl(serverUrl, inputUrl, withApi) { function isTeamUrl(serverUrl, inputUrl, withApi) {
const parsedURL = parseURL(inputUrl); const parsedURL = parseURL(inputUrl);
const server = getServerInfo(serverUrl); const server = getServerInfo(serverUrl);
@@ -76,7 +86,20 @@ function isTeamUrl(serverUrl, inputUrl, withApi) {
return null; 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) { if (withApi) {
nonTeamUrlPaths.push('api'); nonTeamUrlPaths.push('api');
} }
@@ -97,6 +120,20 @@ function isPluginUrl(serverUrl, inputURL) {
parsedURL.pathname.toLowerCase().startsWith('/plugins/'))); 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) { function getServer(inputURL, teams) {
const parsedURL = parseURL(inputURL); const parsedURL = parseURL(inputURL);
if (!parsedURL) { if (!parsedURL) {
@@ -189,6 +226,7 @@ export default {
getServerInfo, getServerInfo,
isTeamUrl, isTeamUrl,
isPluginUrl, isPluginUrl,
isManagedResource,
getDisplayBoundaries, getDisplayBoundaries,
dispatchNotification, dispatchNotification,
getHost, getHost,