MM-19096 – simplify custom login process (#1053)
* simplify custom login process - remove need for temporarily trusting 3rd party hostname * code review tweaks * fix reducer * review tweaks * removing requirement for /login as start
This commit is contained in:
114
src/main.js
114
src/main.js
@@ -372,8 +372,6 @@ function handleAppWebContentsCreated(dc, contents) {
|
|||||||
// initialize custom login tracking
|
// initialize custom login tracking
|
||||||
customLogins[contents.id] = {
|
customLogins[contents.id] = {
|
||||||
inProgress: false,
|
inProgress: false,
|
||||||
startingURL: null,
|
|
||||||
externalHostname: null,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
contents.on('will-attach-webview', (event, webPreferences) => {
|
contents.on('will-attach-webview', (event, webPreferences) => {
|
||||||
@@ -383,60 +381,35 @@ function handleAppWebContentsCreated(dc, contents) {
|
|||||||
|
|
||||||
contents.on('will-navigate', (event, url) => {
|
contents.on('will-navigate', (event, url) => {
|
||||||
const contentID = event.sender.id;
|
const contentID = event.sender.id;
|
||||||
const parsedUrl = new URL(url);
|
const parsedURL = parseURL(url);
|
||||||
const urlIsTrusted = isTrustedURL(parsedUrl);
|
|
||||||
const urlIsTrustedExternalLoginPath = parsedUrl.hostname === customLogins[contentID].externalHostname;
|
|
||||||
|
|
||||||
// don't prevent custom login attempts (oath, saml)
|
if (isTrustedURL(parsedURL)) {
|
||||||
if (!urlIsTrusted && !urlIsTrustedExternalLoginPath) {
|
return;
|
||||||
event.preventDefault();
|
|
||||||
|
|
||||||
// reset custom login if in progress
|
|
||||||
if (customLogins[contentID].inProgress) {
|
|
||||||
customLogins[contentID].inProgress = false;
|
|
||||||
customLogins[contentID].externalHostname = null;
|
|
||||||
|
|
||||||
// redirect to starting url if set
|
|
||||||
if (customLogins[contentID].startingURL) {
|
|
||||||
event.sender.loadURL(customLogins[contentID].startingURL);
|
|
||||||
customLogins[contentID].startingURL = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (customLogins[contentID].inProgress) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
});
|
});
|
||||||
|
|
||||||
// handle custom login requests (oath, saml):
|
// handle custom login requests (oath, saml):
|
||||||
// 1. are we navigating to a supported local custom login path from the `/login` page? (did-start-navigation listener)
|
// 1. are we navigating to a supported local custom login path from the `/login` page?
|
||||||
// - indicate custom login is in progress and store starting point for possible reset
|
// - indicate custom login is in progress
|
||||||
// 2. is a custom login in progress but we don't have the 3rd party hostname yet? (will-redirect listener)
|
// 2. are we finished with the custom login process?
|
||||||
// - store 3rd party hostname to trust subsequent navigation changes within that hostname
|
// - indicate custom login is NOT in progress
|
||||||
// 3. are we finished with the custom login process? (did-start-navigation listener)
|
|
||||||
// - indicate custom login is NOT in progress and clear any stored 3rd party hostname's
|
|
||||||
contents.on('did-start-navigation', (event, url) => {
|
contents.on('did-start-navigation', (event, url) => {
|
||||||
const contentID = event.sender.id;
|
const contentID = event.sender.id;
|
||||||
const parsedUrl = new URL(url);
|
const parsedURL = parseURL(url);
|
||||||
const urlIsTrusted = isTrustedURL(parsedUrl);
|
|
||||||
const urlIsCustomLoginPath = isCustomLoginURL(parsedUrl);
|
|
||||||
const previousPage = event.sender.history[event.sender.history.length - 1];
|
|
||||||
|
|
||||||
if (urlIsTrusted && urlIsCustomLoginPath && !customLogins[contentID].inProgress && previousPage.endsWith('/login')) {
|
if (!isTrustedURL(parsedURL)) {
|
||||||
customLogins[contentID].inProgress = true;
|
return;
|
||||||
customLogins[contentID].startingURL = event.sender.getURL();
|
|
||||||
} else if (urlIsTrusted && customLogins[contentID].inProgress && customLogins[contentID].externalHostname) {
|
|
||||||
customLogins[contentID].inProgress = false;
|
|
||||||
customLogins[contentID].externalHostname = null;
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
contents.on('will-redirect', (event, url) => {
|
if (isCustomLoginURL(parsedURL)) {
|
||||||
const contentID = event.sender.id;
|
customLogins[contentID].inProgress = true;
|
||||||
const parsedUrl = new URL(url);
|
} else if (customLogins[contentID].inProgress) {
|
||||||
const urlIsTrusted = isTrustedURL(parsedUrl);
|
customLogins[contentID].inProgress = false;
|
||||||
const previousPage = event.sender.history[event.sender.history.length - 1];
|
|
||||||
const previousPageIsTrusted = isTrustedURL(previousPage);
|
|
||||||
|
|
||||||
if (!urlIsTrusted && previousPageIsTrusted && customLogins[contentID].inProgress && !customLogins[contentID].externalHostname) {
|
|
||||||
customLogins[contentID].externalHostname = parsedUrl.hostname;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -763,40 +736,49 @@ function handleMainWindowWebContentsCrashed() {
|
|||||||
// helper functions
|
// helper functions
|
||||||
//
|
//
|
||||||
|
|
||||||
function isTrustedURL(url) {
|
function parseURL(url) {
|
||||||
if (!url) {
|
if (!url) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (url instanceof URL) {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return new URL(url);
|
||||||
|
} catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function isTrustedURL(url) {
|
||||||
|
const parsedURL = parseURL(url);
|
||||||
|
if (!parsedURL) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
const teamURLs = config.teams.reduce((urls, team) => {
|
||||||
let parsedUrl = url;
|
const parsedTeamURL = parseURL(team.url);
|
||||||
if (typeof url === 'string') {
|
if (parsedTeamURL) {
|
||||||
try {
|
return urls.concat(parsedTeamURL);
|
||||||
parsedUrl = new URL(url);
|
|
||||||
} catch (e) {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
return urls;
|
||||||
|
}, []);
|
||||||
const trustedURLs = config.teams.map((team) => new URL(team.url));
|
for (const teamURL of teamURLs) {
|
||||||
|
if (parsedURL.origin === teamURL.origin) {
|
||||||
for (const trustedURL of trustedURLs) {
|
|
||||||
if (parsedUrl.origin === trustedURL.origin) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isCustomLoginURL(url) {
|
function isCustomLoginURL(url) {
|
||||||
if (!isTrustedURL(url)) {
|
const parsedURL = parseURL(url);
|
||||||
|
if (!parsedURL) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let parsedUrl = url;
|
if (!isTrustedURL(parsedURL)) {
|
||||||
if (typeof url === 'string') {
|
return false;
|
||||||
parsedUrl = new URL(url);
|
|
||||||
}
|
}
|
||||||
const urlPath = parsedUrl.pathname;
|
const urlPath = parsedURL.pathname;
|
||||||
for (const regexPath of customLoginRegexPaths) {
|
for (const regexPath of customLoginRegexPaths) {
|
||||||
if (urlPath.match(regexPath)) {
|
if (urlPath.match(regexPath)) {
|
||||||
return true;
|
return true;
|
||||||
|
Reference in New Issue
Block a user