Skip to content

Commit

Permalink
fix: Update Authorization Prompt URL to Use URL Anchor Instead of Que…
Browse files Browse the repository at this point in the history
…ry Parameters (WPB-1343) (#15844)

* fix: Update Authorization Prompt URL to Use URL Anchor Instead of Query Parameters for Enhanced Security (WPB-1343)

* replace extra info on url

* remove extra log

* handle signout

* change location search to hash

* remove any type

* better route handling

* extract logic
  • Loading branch information
thisisamir98 committed Sep 28, 2023
1 parent bfbad99 commit 6493135
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 9 deletions.
2 changes: 1 addition & 1 deletion src/script/auth/module/action/RuntimeAction.ts
Expand Up @@ -45,7 +45,7 @@ export class RuntimeAction {
const isOutlookApp = () => {
return Runtime.getBrowserName() === outlookBrowser;
};
const isAuthorizationFlow = () => location?.search?.includes(QUERY_KEY.SCOPE) ?? false;
const isAuthorizationFlow = () => location?.hash?.includes(QUERY_KEY.SCOPE) ?? false;
if (
(!RuntimeSelector.hasToUseDesktopApplication(getState()) && Runtime.isWebappSupportedBrowser()) ||
((isMobileSupportedBrowser() || isOutlookApp()) && isAuthorizationFlow())
Expand Down
10 changes: 7 additions & 3 deletions src/script/auth/page/Login.tsx
Expand Up @@ -74,6 +74,7 @@ import {bindActionCreators, RootState} from '../module/reducer';
import * as AuthSelector from '../module/selector/AuthSelector';
import {QUERY_KEY, ROUTE} from '../route';
import {parseError, parseValidationErrors} from '../util/errorUtil';
import {getOAuthQueryString} from '../util/oauthUtil';

type Props = React.HTMLProps<HTMLDivElement> & {
embedded?: boolean;
Expand Down Expand Up @@ -111,7 +112,7 @@ const LoginComponent = ({
const [verificationCode, setVerificationCode] = useState('');
const [twoFactorSubmitFailedOnce, setTwoFactorSubmitFailedOnce] = useState(false);

const isOauth = UrlUtil.hasURLParameter(QUERY_KEY.SCOPE);
const isOauth = UrlUtil.hasURLParameter(QUERY_KEY.SCOPE, window.location.hash);

const [showEntropyForm, setShowEntropyForm] = useState(false);
const isEntropyRequired = Config.getConfig().FEATURE.ENABLE_EXTRA_CLIENT_ENTROPY;
Expand Down Expand Up @@ -182,7 +183,8 @@ const LoginComponent = ({
await doInitializeClient(ClientType.PERMANENT, undefined, undefined, entropyData);

if (isOauth) {
return navigate(ROUTE.AUTHORIZE);
const queryString = getOAuthQueryString(window.location);
return navigate(`${ROUTE.AUTHORIZE}/${queryString}`);
}
return navigate(ROUTE.HISTORY_INFO);
} catch (error) {
Expand All @@ -206,7 +208,9 @@ const LoginComponent = ({
await doLogin(login, getEntropy);

if (isOauth) {
return navigate(ROUTE.AUTHORIZE);
const queryString = getOAuthQueryString(window.location);

return navigate(`${ROUTE.AUTHORIZE}/${queryString}`);
}
return navigate(ROUTE.HISTORY_INFO);
} catch (error) {
Expand Down
21 changes: 17 additions & 4 deletions src/script/auth/page/Root.tsx
Expand Up @@ -17,7 +17,7 @@
*
*/

import {FC, useEffect} from 'react';
import {FC, ReactNode, useEffect} from 'react';

import {pathWithParams} from '@wireapp/commons/lib/util/UrlUtil';
import {IntlProvider} from 'react-intl';
Expand Down Expand Up @@ -60,10 +60,11 @@ import {bindActionCreators, RootState} from '../module/reducer';
import * as AuthSelector from '../module/selector/AuthSelector';
import * as LanguageSelector from '../module/selector/LanguageSelector';
import {ROUTE} from '../route';
import {getOAuthQueryString} from '../util/oauthUtil';

interface RootProps {}

const Title: FC<{title: string; children: React.ReactNode}> = ({title, children}) => {
const Title: FC<{title: string; children: ReactNode}> = ({title, children}) => {
useEffect(() => {
document.title = title;
}, [title]);
Expand Down Expand Up @@ -106,8 +107,20 @@ const RootComponent: FC<RootProps & ConnectedProps & DispatchProps> = ({
return null;
};

const isAuthenticatedCheck = (page: any): any => (page ? (isAuthenticated ? page : navigate('/auth')) : null);
const isOAuthCheck = (page: any): any => (page ? isAuthenticated ? page : <Navigate to={ROUTE.LOGIN} /> : null);
const isAuthenticatedCheck = (page: ReactNode): ReactNode =>
page ? (isAuthenticated ? page : navigate('/auth')) : null;

const isOAuthCheck = (page: ReactNode): ReactNode => {
if (page) {
if (isAuthenticated) {
return page;
}

const queryString = getOAuthQueryString(window.location);
return queryString ? <Navigate to={`${ROUTE.LOGIN}/${queryString}`} /> : <Navigate to={ROUTE.LOGIN} />;
}
return null;
};

const ProtectedHistoryInfo = () => isAuthenticatedCheck(<HistoryInfo />);
const ProtectedInitialInvite = () => isAuthenticatedCheck(<InitialInvite />);
Expand Down
9 changes: 8 additions & 1 deletion src/script/auth/util/oauthUtil.ts
Expand Up @@ -27,10 +27,17 @@ import {Scope} from '../page/OAuthPermissions';
* @returns OAuthBody
*/
export const oAuthParams = (location: Location) => {
const params = new URLSearchParams(location.search);
const queryString = getOAuthQueryString(location);
const params = new URLSearchParams(queryString ?? location.hash);
return Object.fromEntries(params) as unknown as OAuthBody;
};

export const getOAuthQueryString = (location: Location) => {
const hash = location.hash;
const queryParamIndex = hash.indexOf('?');
return hash.substring(queryParamIndex);
};

/**
* Takes the oauth body and returns the scopes as an array of Scopes accepted by the app.
* @param oauthBody oauth body object
Expand Down

0 comments on commit 6493135

Please sign in to comment.