From 730fe48dd981f4b7fd790c4437f383e869caaa93 Mon Sep 17 00:00:00 2001 From: Adrienne Rio Date: Mon, 2 Dec 2024 15:39:32 +0800 Subject: [PATCH 01/15] chore: regenerate package lock --- package-lock.json | 85 ++++++++++++++++++++++++----------------------- package.json | 2 +- 2 files changed, 45 insertions(+), 42 deletions(-) diff --git a/package-lock.json b/package-lock.json index cfd75a34be1..8ddf213f30a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,7 @@ "@binary-com/binary-style": "^0.2.26", "@binary-com/webtrader-charts": "^0.6.2", "@deriv-com/analytics": "^1.26.1", - "@deriv-com/auth-client": "^1.0.15", + "@deriv-com/auth-client": "^1.2.15", "@deriv-com/quill-ui": "^1.16.2", "@deriv-com/utils": "^0.0.38", "@deriv/deriv-api": "^1.0.15", @@ -2527,49 +2527,30 @@ } }, "node_modules/@deriv-com/auth-client": { - "version": "1.0.15", - "resolved": "https://registry.npmjs.org/@deriv-com/auth-client/-/auth-client-1.0.15.tgz", - "integrity": "sha512-2G6IUtPIX2TmlpW2khDUeltqfsxJtxZgiFdoHidW19rjZYDaj4aHDEh/RXArbiUUKF0i0FGgupzAuW4Id/o7SA==", + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@deriv-com/auth-client/-/auth-client-1.2.15.tgz", + "integrity": "sha512-tplrAeklKg/o1EZZXd6FSowvfwKzebzyUPLk0S/HN/tGeCDljCu8jo2aMXeJGzX9G338686nPYq2EnfeCnVgUg==", "dependencies": { - "@deriv-com/utils": "^0.0.33", - "react": "^18.3.1", - "react-dom": "^18.3.1" + "@deriv-com/utils": "^0.0.42", + "js-cookie": "3.0.5", + "oidc-client-ts": "^3.1.0" + }, + "optionalDependencies": { + "@rollup/rollup-linux-x64-gnu": "^4.27.3" } }, "node_modules/@deriv-com/auth-client/node_modules/@deriv-com/utils": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/@deriv-com/utils/-/utils-0.0.33.tgz", - "integrity": "sha512-LzIpzMvfWhK9y06Qpe/HOB4pFCizk2wAyhv9I0s48Romq+d5MM1mmsuh5CvS4SnzzdLyuBy4rgXrOO3394HB7w==" + "version": "0.0.42", + "resolved": "https://registry.npmjs.org/@deriv-com/utils/-/utils-0.0.42.tgz", + "integrity": "sha512-4JhTpg0sQWCq94RSMGpuT/09bYSV8yO3WdunM2R84qxWNitRH/i4k/xfdleRVzX+xLSmMmJWlkbD6NAlP8U5eg==" }, - "node_modules/@deriv-com/auth-client/node_modules/react": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", - "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", - "dependencies": { - "loose-envify": "^1.1.0" - }, + "node_modules/@deriv-com/auth-client/node_modules/js-cookie": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz", + "integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==", + "license": "MIT", "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@deriv-com/auth-client/node_modules/react-dom": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", - "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.2" - }, - "peerDependencies": { - "react": "^18.3.1" - } - }, - "node_modules/@deriv-com/auth-client/node_modules/scheduler": { - "version": "0.23.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", - "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", - "dependencies": { - "loose-envify": "^1.1.0" + "node": ">=14" } }, "node_modules/@deriv-com/quill-tokens": { @@ -3244,12 +3225,13 @@ "integrity": "sha512-yNN7S2HHh2is9WrLlfEnPdX5rO9Nlv3wmBXSWXXQTt9mAC5PU/NFQRfGGI/fBNRSQA4PGqgz5LYHwTcHhEwXeQ==" }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.20.0.tgz", - "integrity": "sha512-y+eoL2I3iphUg9tN9GB6ku1FA8kOfmF4oUEWhztDJ4KXJy1agk/9+pejOuZkNFhRwHAOxMsBPLbXPd6mJiCwew==", + "version": "4.28.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.28.0.tgz", + "integrity": "sha512-Nl4KIzteVEKE9BdAvYoTkW19pa7LR/RBrT6F1dJCV/3pbjwDcaOq+edkP0LXuJ9kflW/xOK414X78r+K84+msw==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -12181,6 +12163,15 @@ "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz", "integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==" }, + "node_modules/jwt-decode": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-4.0.0.tgz", + "integrity": "sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -16422,6 +16413,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/oidc-client-ts": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/oidc-client-ts/-/oidc-client-ts-3.1.0.tgz", + "integrity": "sha512-IDopEXjiwjkmJLYZo6BTlvwOtnlSniWZkKZoXforC/oLZHC9wkIxd25Kwtmo5yKFMMVcsp3JY6bhcNJqdYk8+g==", + "license": "Apache-2.0", + "dependencies": { + "jwt-decode": "^4.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", diff --git a/package.json b/package.json index a0c3ec3bbcc..c3925b24fe4 100644 --- a/package.json +++ b/package.json @@ -107,7 +107,7 @@ "@binary-com/binary-style": "^0.2.26", "@binary-com/webtrader-charts": "^0.6.2", "@deriv-com/analytics": "^1.26.1", - "@deriv-com/auth-client": "^1.0.15", + "@deriv-com/auth-client": "^1.2.15", "@deriv-com/quill-ui": "^1.16.2", "@deriv-com/utils": "^0.0.38", "@deriv/deriv-api": "^1.0.15", From 1110bd3c3114791eb0e775bfe47211b3cf9d57e5 Mon Sep 17 00:00:00 2001 From: Adrienne Rio Date: Mon, 2 Dec 2024 15:48:04 +0800 Subject: [PATCH 02/15] feat: migrated oidc implementation from old pr --- scripts/config/pages.js | 3 +- src/javascript/_common/auth.js | 83 +++++++++-- src/javascript/app/base/binary_pages.js | 2 + src/javascript/app/base/callback.js | 16 ++ src/javascript/app/base/header.js | 92 +++++++----- src/javascript/app/base/logged_in.js | 2 - src/javascript/app/base/page.js | 2 + .../app/pages/callback/callback.jsx | 137 ++++++++++++++++++ src/javascript/app/pages/deriv_iframe.jsx | 19 --- src/templates/_common/_layout/layout.jsx | 1 - .../_common/includes/deriv-iframe.jsx | 5 - src/templates/app/callback.jsx | 30 ++++ src/templates/app/logged_in.jsx | 1 - 13 files changed, 315 insertions(+), 78 deletions(-) create mode 100644 src/javascript/app/base/callback.js create mode 100644 src/javascript/app/pages/callback/callback.jsx delete mode 100644 src/javascript/app/pages/deriv_iframe.jsx delete mode 100644 src/templates/_common/includes/deriv-iframe.jsx create mode 100644 src/templates/app/callback.jsx diff --git a/scripts/config/pages.js b/scripts/config/pages.js index 370d3179c2b..e9a98f8add6 100644 --- a/scripts/config/pages.js +++ b/scripts/config/pages.js @@ -64,6 +64,7 @@ module.exports = [ // ['dialog', 'app/dialog', null], ['explanation', 'app/trade/explanation', null], ['logged_inws', 'app/logged_in', null], + ['callback', 'app/callback', null], // ['redirect', 'app/logged_in', null, 'Redirecting...'], // ==================== Section: "static" ==================== @@ -120,4 +121,4 @@ module.exports = [ // ['graduates', 'landing_pages/graduate_program', null, 'Binary.com Graduate Program', 'NOT-en'], // ['hackathon', 'landing_pages/hackathon', null, 'Hackathon Competition', 'NOT-en'], // ['introducing-usb', 'landing_pages/usb', null, 'Introducing USB', 'NOT-en'], -]; +]; \ No newline at end of file diff --git a/src/javascript/_common/auth.js b/src/javascript/_common/auth.js index 6a54713b52c..73bdbad0d12 100644 --- a/src/javascript/_common/auth.js +++ b/src/javascript/_common/auth.js @@ -5,6 +5,8 @@ const { URLConstants, WebSocketUtils, } = require('@deriv-com/utils'); +const Cookies = require('js-cookie'); +const requestOidcAuthentication = require('@deriv-com/auth-client').requestOidcAuthentication; const Analytics = require('./analytics'); export const DEFAULT_OAUTH_LOGOUT_URL = 'https://oauth.deriv.com/oauth2/sessions/logout'; @@ -79,22 +81,33 @@ export const isOAuth2Enabled = () => { export const getLogoutHandler = onWSLogoutAndRedirect => { const isAuthEnabled = isOAuth2Enabled(); + let timeout; if (!isAuthEnabled) { return onWSLogoutAndRedirect; } - const onMessage = async event => { - const allowedOrigin = getOAuthOrigin(); - if (allowedOrigin === event.origin) { - if (event.data === 'logout_complete') { - try { - await onWSLogoutAndRedirect(); - } catch (err) { - // eslint-disable-next-line no-console - console.error(`logout was completed successfully on oauth hydra server, but logout handler returned error: ${err}`); - } + const cleanup = () => { + clearTimeout(timeout); + + const iframe = document.getElementById('logout-iframe'); + if (iframe) iframe.remove(); + }; + + const onMessage = event => { + if (event.data === 'logout_complete') { + const domains = ['deriv.com', 'binary.sx', 'pages.dev', 'localhost']; + const currentDomain = window.location.hostname.split('.').slice(-2).join('.'); + if (domains.includes(currentDomain)) { + Cookies.set('logged_state', 'false', { + expires: 30, + path : '/', + secure : true, + }); } + onWSLogoutAndRedirect(); + window.removeEventListener('message', onMessage); + cleanup(); } }; @@ -113,8 +126,10 @@ export const getLogoutHandler = onWSLogoutAndRedirect => { iframe.style.display = 'none'; document.body.appendChild(iframe); - setTimeout(() => { + timeout = setTimeout(() => { onWSLogoutAndRedirect(); + window.removeEventListener('message', onMessage); + cleanup(); }, LOGOUT_HANDLER_TIMEOUT); } @@ -123,3 +138,49 @@ export const getLogoutHandler = onWSLogoutAndRedirect => { return oAuth2Logout; }; + +export const requestSingleSignOn = async () => { + const _requestSingleSignOn = async () => { + // if we have previously logged in, + // this cookie will be set by the Callback page (which is exported from @deriv-com/auth-client library) to true when we have successfully logged in from other apps + const isLoggedInCookie = Cookies.get('logged_state') === 'true'; + const clientAccounts = JSON.parse(localStorage.getItem('client.accounts') || '{}'); + const isClientAccountsPopulated = Object.keys(clientAccounts).length > 0; + const isAuthEnabled = isOAuth2Enabled(); + const isCallbackPage = window.location.pathname.includes('callback'); + const isEndpointPage = window.location.pathname.includes('endpoint'); + + // we only do SSO if: + // we have previously logged-in before from SmartTrader or any other apps (Deriv.app, etc) - isLoggedInCookie + // if we are not in the callback route to prevent re-calling this function - !isCallbackPage + // if client.accounts in localStorage is empty - !isClientAccountsPopulated + // and if feature flag for OIDC Phase 2 is enabled - isAuthEnabled + if (isLoggedInCookie && !isCallbackPage && !isEndpointPage && !isClientAccountsPopulated && isAuthEnabled) { + await requestOidcAuthentication({ + redirectCallbackUri: `${window.location.origin}/en/callback`, + }); + } + }; + + const isGrowthbookLoaded = Analytics.isGrowthbookLoaded(); + if (!isGrowthbookLoaded) { + let retryInterval = 0; + // this interval is to check if Growthbook is already initialised. + // If not, keep checking it (max 10 times) and SSO if conditions are met + const interval = setInterval(() => { + if (retryInterval > 10) { + clearInterval(interval); + } else { + const isLoaded = Analytics.isGrowthbookLoaded(); + if (isLoaded) { + _requestSingleSignOn(); + clearInterval(interval); + } else { + retryInterval += 1; + } + } + }, 500); + } else { + _requestSingleSignOn(); + } +}; diff --git a/src/javascript/app/base/binary_pages.js b/src/javascript/app/base/binary_pages.js index b35779f60d7..4ec8f9d00c0 100644 --- a/src/javascript/app/base/binary_pages.js +++ b/src/javascript/app/base/binary_pages.js @@ -3,6 +3,7 @@ // ==================== app ==================== const LoggedInHandler = require('./logged_in'); +const CallbackHandler = require('./callback'); // const Redirect = require('./redirect'); // const AccountTransfer = require('../pages/cashier/account_transfer'); // const Cashier = require('../pages/cashier/cashier'); @@ -98,6 +99,7 @@ const pages_config = { // landing_page : { module: StaticPages.LandingPage, is_authenticated: true, only_virtual: true }, // limitsws : { module: Limits, is_authenticated: true, no_mf: true, only_real: true, needs_currency: true }, logged_inws: { module: LoggedInHandler }, + callback : { module: CallbackHandler }, // lost_passwordws : { module: LostPassword, not_authenticated: true }, // malta : { module: StaticPages.Locations }, // maltainvestws : { module: FinancialAccOpening, is_authenticated: true }, diff --git a/src/javascript/app/base/callback.js b/src/javascript/app/base/callback.js new file mode 100644 index 00000000000..6a1db2c0563 --- /dev/null +++ b/src/javascript/app/base/callback.js @@ -0,0 +1,16 @@ +const SocketCache = require('../../_common/base/socket_cache'); +const CallbackElement = require('../pages/callback/callback.jsx'); + +const CallbackHandler = (() => { + const onLoad = async () => { + parent.window.is_logging_in = 1; // this flag is used in base.js to prevent auto-reloading this page + CallbackElement.init(); + SocketCache.clear(); + }; + + return { + onLoad, + }; +})(); + +module.exports = CallbackHandler; diff --git a/src/javascript/app/base/header.js b/src/javascript/app/base/header.js index 5f29ce9a82b..dabcf07a787 100644 --- a/src/javascript/app/base/header.js +++ b/src/javascript/app/base/header.js @@ -1,33 +1,33 @@ // const BinaryPjax = require('./binary_pjax'); -const Client = require('./client'); -const BinarySocket = require('./socket'); -const AuthClient = require('../../_common/auth'); -const showHidePulser = require('../common/account_opening').showHidePulser; -const updateTotal = require('../pages/user/update_total'); -const isAuthenticationAllowed = require('../../_common/base/client_base').isAuthenticationAllowed; -const GTM = require('../../_common/base/gtm'); -const Login = require('../../_common/base/login'); -const SocketCache = require('../../_common/base/socket_cache'); +const requestOidcAuthentication = require('@deriv-com/auth-client').requestOidcAuthentication; +const Client = require('./client'); +const BinarySocket = require('./socket'); +const AuthClient = require('../../_common/auth'); +const showHidePulser = require('../common/account_opening').showHidePulser; +const updateTotal = require('../pages/user/update_total'); +const isAuthenticationAllowed = require('../../_common/base/client_base').isAuthenticationAllowed; +const GTM = require('../../_common/base/gtm'); +const Login = require('../../_common/base/login'); +const SocketCache = require('../../_common/base/socket_cache'); // const elementInnerHtml = require('../../_common/common_functions').elementInnerHtml; -const getElementById = require('../../_common/common_functions').getElementById; -const localize = require('../../_common/localize').localize; -const localizeKeepPlaceholders = require('../../_common/localize').localizeKeepPlaceholders; -const State = require('../../_common/storage').State; -const Url = require('../../_common/url'); -const applyToAllElements = require('../../_common/utility').applyToAllElements; -const createElement = require('../../_common/utility').createElement; -const findParent = require('../../_common/utility').findParent; -const getTopLevelDomain = require('../../_common/utility').getTopLevelDomain; -const getPlatformSettings = require('../../../templates/_common/brand.config').getPlatformSettings; -const getHostname = require('../../_common/utility').getHostname; -const template = require('../../_common/utility').template; -const Language = require('../../_common/language'); -const mapCurrencyName = require('../../_common/base/currency_base').mapCurrencyName; -const isEuCountry = require('../common/country_base').isEuCountry; -const DerivIFrame = require('../pages/deriv_iframe.jsx'); -const DerivLiveChat = require('../pages/livechat.jsx'); -const openChat = require('../../_common/utility.js').openChat; -const getRemoteConfig = require('../hooks/useRemoteConfig').getRemoteConfig; +const getElementById = require('../../_common/common_functions').getElementById; +const localize = require('../../_common/localize').localize; +const localizeKeepPlaceholders = require('../../_common/localize').localizeKeepPlaceholders; +const State = require('../../_common/storage').State; +const Url = require('../../_common/url'); +const applyToAllElements = require('../../_common/utility').applyToAllElements; +const createElement = require('../../_common/utility').createElement; +const findParent = require('../../_common/utility').findParent; +const getTopLevelDomain = require('../../_common/utility').getTopLevelDomain; +const getPlatformSettings = require('../../../templates/_common/brand.config').getPlatformSettings; +const getHostname = require('../../_common/utility').getHostname; +const template = require('../../_common/utility').template; +const Language = require('../../_common/language'); +const mapCurrencyName = require('../../_common/base/currency_base').mapCurrencyName; +const isEuCountry = require('../common/country_base').isEuCountry; +const DerivLiveChat = require('../pages/livechat.jsx'); +const openChat = require('../../_common/utility.js').openChat; +const getRemoteConfig = require('../hooks/useRemoteConfig').getRemoteConfig; const header_icon_base_path = '/images/pages/header/'; const wallet_header_icon_base_path = '/images/pages/header/wallets/'; @@ -45,7 +45,6 @@ const Header = (() => { }; const onLoad = () => { - DerivIFrame.init(); populateAccountsList(); populateWalletAccounts(); bindSvg(); @@ -650,11 +649,25 @@ const Header = (() => { // } // }; - const loginOnClick = (e) => { + const loginOnClick = async (e) => { e.preventDefault(); - Login.redirectToLogin(); + const isOAuth2Enabled = AuthClient.isOAuth2Enabled(); + + if (isOAuth2Enabled) { + const redirectCallbackUri = `${window.location.origin}/en/callback`; + const postLoginRedirectUri = window.location.href; + const postLogoutRedirectUri = `${window.location.origin}/en/trading`; + // Test commit + await requestOidcAuthentication({ + redirectCallbackUri, + postLoginRedirectUri, + postLogoutRedirectUri, + }); + } else { + Login.redirectToLogin(); + } }; - + const logoutOnClick = async () => { window.fcWidget?.user.clear().then( () => window.fcWidget.destroy(), @@ -663,8 +676,10 @@ const Header = (() => { // This will wrap the logout call Client.sendLogoutRequest with our own logout iframe, which is to inform Hydra that the user is logging out // and the session should be cleared on Hydra's side. Once this is done, it will call the passed-in logout handler Client.sendLogoutRequest. // If Hydra authentication is not enabled, the logout handler Client.sendLogoutRequest will just be called instead. - const onLogoutWithOauth = await AuthClient.getLogoutHandler(Client.sendLogoutRequest); - + const onLogoutWithOauth = await AuthClient.getLogoutHandler( + Client.sendLogoutRequest + ); + onLogoutWithOauth(); }; @@ -891,13 +906,14 @@ const Header = (() => { const account_switcher_seperator = document.getElementById('cfd-link-seperator'); const multiplier_text = localize('Multipliers'); const account_header = document.querySelectorAll('.header__accounts-multiple'); + const is_callback_page = window.location.pathname.includes('callback'); let is_virtual; if (current_active_login) { is_virtual = current_active_login.startsWith('VRTC'); } const showTradersHubLink = (show) => { - traders_hub_link.style.display = show ? 'flex' : 'none'; - account_switcher_seperator.style.display = show ? 'block' : 'none'; + if (traders_hub_link.style) traders_hub_link.style.display = show ? 'flex' : 'none'; + if (account_switcher_seperator.style) account_switcher_seperator.style.display = show ? 'block' : 'none'; }; account_header.forEach(header => { @@ -908,8 +924,8 @@ const Header = (() => { $(`${multiplier_text}`).insertAfter('#header__acc-balance'); } - if (has_real_account) showTradersHubLink(true); - if (is_virtual) showTradersHubLink(true); + if (has_real_account && !is_callback_page) showTradersHubLink(true); + if (is_virtual && !is_callback_page) showTradersHubLink(true); if (is_virtual || !has_real_account) { manage_acc_btn.style.visibility = 'hidden'; } diff --git a/src/javascript/app/base/logged_in.js b/src/javascript/app/base/logged_in.js index 2a250d20dcd..0c081b0e3b2 100644 --- a/src/javascript/app/base/logged_in.js +++ b/src/javascript/app/base/logged_in.js @@ -12,7 +12,6 @@ const removeCookies = require('../../_common/storage').removeCookies; const paramsHash = require('../../_common/url').paramsHash; const urlFor = require('../../_common/url').urlFor; const getPropertyValue = require('../../_common/utility').getPropertyValue; -const DerivIFrame = require('../pages/deriv_iframe.jsx'); const LoggedInHandler = (() => { const onLoad = () => { @@ -20,7 +19,6 @@ const LoggedInHandler = (() => { parent.window.is_logging_in = 1; // this flag is used in base.js to prevent auto-reloading this page let redirect_url; const params = paramsHash(window.location.href); - DerivIFrame.init(); BinarySocket.send({ authorize: params.token1 }).then((response) => { const account_list = getPropertyValue(response, ['authorize', 'account_list']); if (isStorageSupported(localStorage) && isStorageSupported(sessionStorage) && account_list) { diff --git a/src/javascript/app/base/page.js b/src/javascript/app/base/page.js index 9b9d7282427..b5883366ce2 100644 --- a/src/javascript/app/base/page.js +++ b/src/javascript/app/base/page.js @@ -23,6 +23,7 @@ const toISOFormat = require('../../_common/string_util').toISOFormat; const Url = require('../../_common/url'); const Analytics = require('../../_common/analytics'); const { openChatWithParam } = require('../../_common/utility'); +const { requestSingleSignOn } = require('../../_common/auth'); const createElement = require('../../_common/utility').createElement; const isLoginPages = require('../../_common/utility').isLoginPages; const isProduction = require('../../config').isProduction; @@ -100,6 +101,7 @@ const Page = (() => { updateLinksURL('#content'); } else { init(); + requestSingleSignOn(); if (!isLoginPages()) { Language.setCookie(Language.urlLang()); const url_query_strings = Url.paramsHash(); diff --git a/src/javascript/app/pages/callback/callback.jsx b/src/javascript/app/pages/callback/callback.jsx new file mode 100644 index 00000000000..7c47b26641e --- /dev/null +++ b/src/javascript/app/pages/callback/callback.jsx @@ -0,0 +1,137 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; + +import { Callback } from '@deriv-com/auth-client'; + +import Cookies from 'js-cookie'; +import moment from 'moment'; +import Client from '../../base/client'; +import BinarySocket from '../../base/socket'; +import GTM from '../../../_common/base/gtm'; +import { get as getLanguage, urlLang } from '../../../_common/language'; +import { isStorageSupported, removeCookies } from '../../../_common/storage'; +import { urlFor } from '../../../_common/url'; +import { getPropertyValue } from '../../../_common/utility'; +import { getElementById } from '../../../_common/common_functions'; + +const map_names = { + country : 'residence', + landing_company_name: 'landing_company_shortcode', +}; + +const storeClientAccounts = (tokens, account_list) => { + // Parse url for loginids, tokens, and currencies returned by OAuth + + // Clear all accounts before entering the loop + Client.clearAllAccounts(); + + account_list.forEach(account => { + Object.keys(account).forEach(param => { + if (param === 'loginid') { + if (!Client.get('loginid') && !account.is_disabled && !account.is_virtual) { + Client.set(param, account[param]); + } + } else { + const param_to_set = map_names[param] || param; + const value_to_set = typeof account[param] === 'undefined' ? '' : account[param]; + Client.set(param_to_set, value_to_set, account.loginid); + } + }); + }); + + let i = 1; + while (tokens[`acct${i}`]) { + const loginid = tokens[`acct${i}`]; + const token = tokens[`token${i}`]; + if (loginid && token) { + Client.set('token', token, loginid); + } + i++; + } + + // if didn't find any login ID that matched the above condition + // or the selected one doesn't have a token, set the first one + if (!Client.get('loginid') || !Client.get('token')) { + Client.set('loginid', tokens.acct1 || account_list[0].loginid); + } + + if (Client.isLoggedIn()) { + GTM.setLoginFlag('log_in'); + Client.set('session_start', parseInt(moment().valueOf() / 1000)); + // Remove cookies that were set by the old code + removeCookies('email', 'login', 'loginid', 'loginid_list', 'residence'); + } +}; + +const CallbackContainer = () => { + const onLoginSuccess = async tokens => { + let redirect_url; + BinarySocket.send({ authorize: tokens.token1 }).then(response => { + const account_list = getPropertyValue(response, ['authorize', 'account_list']); + if ( + isStorageSupported(localStorage) && + isStorageSupported(sessionStorage) && + account_list + ) { + // redirect url + redirect_url = sessionStorage.getItem('redirect_url'); + sessionStorage.removeItem('redirect_url'); + + storeClientAccounts(tokens, account_list); + } else { + Client.doLogout({ logout: 1 }); + } + + // redirect back + let set_default = true; + if (redirect_url) { + const do_not_redirect = [ + 'reset_passwordws', + 'lost_passwordws', + 'change_passwordws', + 'home', + '404', + ]; + const reg = new RegExp(do_not_redirect.join('|'), 'i'); + if (!reg.test(redirect_url) && urlFor('') !== redirect_url) { + set_default = false; + } + } + if (set_default) { + const lang_cookie = urlLang(redirect_url) || Cookies.get('language'); + const language = getLanguage(); + redirect_url = + Client.isAccountOfType('financial') || Client.isOptionsBlocked() + ? urlFor('user/metatrader') + : Client.defaultRedirectUrl(); + if (lang_cookie && lang_cookie !== language) { + redirect_url = redirect_url.replace( + new RegExp(`/${language}/`, 'i'), + `/${lang_cookie.toLowerCase()}/` + ); + } + } + getElementById('loading_link').setAttribute('href', redirect_url); + const domains = ['deriv.com', 'binary.sx', 'pages.dev', 'localhost']; + const currentDomain = window.location.hostname.split('.').slice(-2).join('.'); + if (domains.includes(currentDomain)) { + Cookies.set('logged_state', 'false', { + expires: 30, + path : '/', + domain : currentDomain, + secure : true, + }); + } + window.location.href = redirect_url; // need to redirect not using pjax + }); + }; + + // eslint-disable-next-line no-console + return ; +}; + +export const init = () => { + ReactDOM.render(, document.getElementById('callback_container')); +}; + +export default init; diff --git a/src/javascript/app/pages/deriv_iframe.jsx b/src/javascript/app/pages/deriv_iframe.jsx deleted file mode 100644 index 82781c14f79..00000000000 --- a/src/javascript/app/pages/deriv_iframe.jsx +++ /dev/null @@ -1,19 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import { isOAuth2Enabled } from '../../_common/auth'; - -const DerivIFrame = () => ( -