forked from Ivasoft/mattermost-mobile
* Handle SSO redirecting to a different URL than specified by the user * Set Server URL based on the last redirect * Improve last redirect condition Co-authored-by: Elias Nahum <nahumhbl@gmail.com>
This commit is contained in:
@@ -147,19 +147,19 @@ export default class SelectServer extends PureComponent {
|
||||
}
|
||||
};
|
||||
|
||||
getUrl = () => {
|
||||
const urlParse = require('url-parse');
|
||||
let preUrl = urlParse(this.state.url, true);
|
||||
getUrl = async (serverUrl, useHttp = false) => {
|
||||
let url = this.sanitizeUrl(serverUrl, useHttp);
|
||||
|
||||
if (!preUrl.host || preUrl.protocol === 'file:') {
|
||||
preUrl = urlParse('https://' + stripTrailingSlashes(this.state.url), true);
|
||||
try {
|
||||
const resp = await fetch(url, {method: 'HEAD'});
|
||||
if (resp?.rnfbRespInfo?.redirects?.length) {
|
||||
url = resp.rnfbRespInfo.redirects[resp.rnfbRespInfo.redirects.length - 1];
|
||||
}
|
||||
} catch {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
if (preUrl.protocol === 'http:') {
|
||||
preUrl.protocol = 'https:';
|
||||
}
|
||||
|
||||
return stripTrailingSlashes(preUrl.protocol + '//' + preUrl.host + preUrl.pathname);
|
||||
return this.sanitizeUrl(url, useHttp);
|
||||
};
|
||||
|
||||
goToNextScreen = (screen, title, passProps = {}, navOptions = {}) => {
|
||||
@@ -187,8 +187,6 @@ export default class SelectServer extends PureComponent {
|
||||
};
|
||||
|
||||
handleConnect = preventDoubleTap(async () => {
|
||||
const url = this.getUrl();
|
||||
|
||||
Keyboard.dismiss();
|
||||
|
||||
if (this.state.connecting || this.state.connected) {
|
||||
@@ -197,7 +195,7 @@ export default class SelectServer extends PureComponent {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isValidUrl(url)) {
|
||||
if (!isValidUrl(this.sanitizeUrl(this.state.url))) {
|
||||
this.setState({
|
||||
error: {
|
||||
intl: {
|
||||
@@ -219,11 +217,11 @@ export default class SelectServer extends PureComponent {
|
||||
auto: true,
|
||||
certificate,
|
||||
}).build();
|
||||
this.pingServer(url);
|
||||
this.pingServer(this.state.url);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.pingServer(url);
|
||||
this.pingServer(this.state.url);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -301,7 +299,7 @@ export default class SelectServer extends PureComponent {
|
||||
resetToChannel();
|
||||
};
|
||||
|
||||
pingServer = (url, retryWithHttp = true) => {
|
||||
pingServer = async (url, retryWithHttp = true) => {
|
||||
const {
|
||||
getPing,
|
||||
handleServerUrlChanged,
|
||||
@@ -315,8 +313,9 @@ export default class SelectServer extends PureComponent {
|
||||
error: null,
|
||||
});
|
||||
|
||||
Client4.setUrl(url);
|
||||
handleServerUrlChanged(url);
|
||||
const serverUrl = await this.getUrl(url, !retryWithHttp);
|
||||
Client4.setUrl(serverUrl);
|
||||
handleServerUrlChanged(serverUrl);
|
||||
|
||||
let cancel = false;
|
||||
this.cancelPing = () => {
|
||||
@@ -330,13 +329,16 @@ export default class SelectServer extends PureComponent {
|
||||
this.cancelPing = null;
|
||||
};
|
||||
|
||||
getPing().then((result) => {
|
||||
try {
|
||||
const result = await getPing();
|
||||
|
||||
if (cancel) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.error && retryWithHttp) {
|
||||
this.pingServer(url.replace('https:', 'http:'), false);
|
||||
const nurl = serverUrl.replace('https:', 'http:');
|
||||
this.pingServer(nurl, false);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -350,7 +352,7 @@ export default class SelectServer extends PureComponent {
|
||||
connecting: false,
|
||||
error: result.error,
|
||||
});
|
||||
}).catch(() => {
|
||||
} catch {
|
||||
if (cancel) {
|
||||
return;
|
||||
}
|
||||
@@ -358,9 +360,23 @@ export default class SelectServer extends PureComponent {
|
||||
this.setState({
|
||||
connecting: false,
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
sanitizeUrl = (url, useHttp = false) => {
|
||||
const urlParse = require('url-parse');
|
||||
let preUrl = urlParse(url, true);
|
||||
|
||||
if (!preUrl.host || preUrl.protocol === 'file:') {
|
||||
preUrl = urlParse('https://' + stripTrailingSlashes(url), true);
|
||||
}
|
||||
|
||||
if (preUrl.protocol === 'http:' && !useHttp) {
|
||||
preUrl.protocol = 'https:';
|
||||
}
|
||||
return stripTrailingSlashes(preUrl.protocol + '//' + preUrl.host + preUrl.pathname);
|
||||
}
|
||||
|
||||
scheduleSessionExpiredNotification = () => {
|
||||
const {intl} = this.context;
|
||||
const {actions} = this.props;
|
||||
|
||||
@@ -87,15 +87,15 @@ class SSO extends PureComponent {
|
||||
switch (props.ssoType) {
|
||||
case ViewTypes.GITLAB:
|
||||
this.loginUrl = `${props.serverUrl}/oauth/gitlab/mobile_login`;
|
||||
this.completedUrl = '/signup/gitlab/complete';
|
||||
this.completeUrlPath = '/signup/gitlab/complete';
|
||||
break;
|
||||
case ViewTypes.SAML:
|
||||
this.loginUrl = `${props.serverUrl}/login/sso/saml?action=mobile`;
|
||||
this.completedUrl = '/login/sso/saml';
|
||||
this.completeUrlPath = '/login/sso/saml';
|
||||
break;
|
||||
case ViewTypes.OFFICE365:
|
||||
this.loginUrl = `${props.serverUrl}/oauth/office365/mobile_login`;
|
||||
this.completedUrl = '/signup/office365/complete';
|
||||
this.completeUrlPath = '/signup/office365/complete';
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ class SSO extends PureComponent {
|
||||
|
||||
if (parsed.host.includes('.onelogin.com')) {
|
||||
nextState.jsCode = oneLoginFormScalingJS;
|
||||
} else if (parsed.pathname === this.completedUrl) {
|
||||
} else if (parsed.pathname === this.completeUrlPath) {
|
||||
// To avoid `window.postMessage` conflicts in any of the SSO flows
|
||||
// we enable the onMessage handler only When the webView navigates to the final SSO URL.
|
||||
nextState.messagingEnabled = true;
|
||||
@@ -150,8 +150,15 @@ class SSO extends PureComponent {
|
||||
|
||||
onLoadEnd = (event) => {
|
||||
const url = event.nativeEvent.url;
|
||||
if (url.includes(this.completedUrl)) {
|
||||
CookieManager.get(this.props.serverUrl, this.useWebkit).then((res) => {
|
||||
const parsed = urlParse(url);
|
||||
|
||||
let isLastRedirect = url.includes(this.completeUrlPath);
|
||||
if (this.props.ssoType === ViewTypes.SAML) {
|
||||
isLastRedirect = isLastRedirect && !parsed.query;
|
||||
}
|
||||
|
||||
if (isLastRedirect) {
|
||||
CookieManager.get(parsed.origin, this.useWebkit).then((res) => {
|
||||
const mmtoken = res.MMAUTHTOKEN;
|
||||
const token = typeof mmtoken === 'object' ? mmtoken.value : mmtoken;
|
||||
|
||||
@@ -162,6 +169,13 @@ class SSO extends PureComponent {
|
||||
} = this.props.actions;
|
||||
|
||||
Client4.setToken(token);
|
||||
if (this.props.serverUrl !== parsed.origin) {
|
||||
const original = urlParse(this.props.serverUrl);
|
||||
|
||||
// Check whether we need to set a sub-path
|
||||
parsed.set('pathname', original.pathname || '');
|
||||
Client4.setUrl(parsed.href);
|
||||
}
|
||||
ssoLogin(token).then((result) => {
|
||||
if (result.error) {
|
||||
this.onLoadEndError(result.error);
|
||||
|
||||
Reference in New Issue
Block a user