-
Notifications
You must be signed in to change notification settings - Fork 61
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adrienne / Integrate Hydra authentication #821
Changes from all commits
753bb65
de69d69
be1724f
d28a2d8
893884d
5dee70e
b05de9c
157fa60
fbe651f
690317d
36bfba6
5a90f66
2601575
1105aa0
10202f8
4e9ade8
4286a60
bad20f6
b339eda
b3df698
7c03bb1
0deec9e
4a93343
03d6000
3b5332b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
const DerivAnalytics = require('@deriv-com/analytics'); | ||
|
||
const Analytics = (() => { | ||
const init = () => { | ||
if (process.env.RUDDERSTACK_KEY && process.env.GROWTHBOOK_CLIENT_KEY) { | ||
DerivAnalytics.Analytics.initialise({ | ||
growthbookKey : process.env.GROWTHBOOK_CLIENT_KEY, // optional key to enable A/B tests | ||
rudderstackKey: process.env.RUDDERSTACK_KEY, | ||
}); | ||
} | ||
}; | ||
|
||
const isGrowthbookLoaded = () => Boolean(DerivAnalytics.Analytics?.getInstances()?.ab); | ||
|
||
const getGrowthbookFeatureValue = ({ defaultValue, featureFlag }) => { | ||
const resolvedDefaultValue = defaultValue !== undefined ? defaultValue : false; | ||
const isGBLoaded = isGrowthbookLoaded(); | ||
|
||
if (!isGBLoaded) return [null, false]; | ||
|
||
return [DerivAnalytics.Analytics?.getFeatureValue(featureFlag, resolvedDefaultValue), true]; | ||
}; | ||
|
||
const setGrowthbookOnChange = onChange => { | ||
const isGBLoaded = isGrowthbookLoaded(); | ||
if (!isGBLoaded) return null; | ||
|
||
const onChangeRenderer = DerivAnalytics.Analytics?.getInstances().ab.GrowthBook?.setRenderer(() => { | ||
onChange(); | ||
}); | ||
return onChangeRenderer; | ||
}; | ||
|
||
return { | ||
init, | ||
isGrowthbookLoaded, | ||
getGrowthbookFeatureValue, | ||
setGrowthbookOnChange, | ||
}; | ||
})(); | ||
|
||
module.exports = Analytics; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
const { | ||
AppIDConstants, | ||
LocalStorageConstants, | ||
LocalStorageUtils, | ||
URLConstants, | ||
WebSocketUtils, | ||
} = require('@deriv-com/utils'); | ||
const Analytics = require('./analytics'); | ||
|
||
export const DEFAULT_OAUTH_LOGOUT_URL = 'https://oauth.deriv.com/oauth2/sessions/logout'; | ||
|
||
export const DEFAULT_OAUTH_ORIGIN_URL = 'https://oauth.deriv.com'; | ||
|
||
const LOGOUT_HANDLER_TIMEOUT = 10000; | ||
|
||
const SocketURL = { | ||
[URLConstants.derivP2pProduction]: 'blue.derivws.com', | ||
[URLConstants.derivP2pStaging] : 'red.derivws.com', | ||
}; | ||
|
||
export const getServerInfo = () => { | ||
const origin = window.location.origin; | ||
const hostname = window.location.hostname; | ||
|
||
const existingAppId = LocalStorageUtils.getValue(LocalStorageConstants.configAppId); | ||
const existingServerUrl = LocalStorageUtils.getValue(LocalStorageConstants.configServerURL); | ||
// since we don't have official app_id for staging, | ||
// we will use the red server with app_id=62019 for the staging-p2p.deriv.com for now | ||
// to fix the login issue | ||
if (origin === URLConstants.derivP2pStaging && (!existingAppId || !existingServerUrl)) { | ||
LocalStorageUtils.setValue(LocalStorageConstants.configServerURL, SocketURL[origin]); | ||
LocalStorageUtils.setValue(LocalStorageConstants.configAppId, `${AppIDConstants.domainAppId[hostname]}`); | ||
} | ||
|
||
const serverUrl = LocalStorageUtils.getValue(LocalStorageConstants.configServerURL) || localStorage.getItem('config.server_url') || 'oauth.deriv.com'; | ||
|
||
const defaultAppId = WebSocketUtils.getAppId(); | ||
const appId = LocalStorageUtils.getValue(LocalStorageConstants.configAppId) || defaultAppId; | ||
const lang = LocalStorageUtils.getValue(LocalStorageConstants.i18nLanguage) || 'en'; | ||
|
||
return { | ||
appId, | ||
lang, | ||
serverUrl, | ||
}; | ||
}; | ||
|
||
export const getOAuthLogoutUrl = () => { | ||
const { appId, serverUrl } = getServerInfo(); | ||
|
||
const oauthUrl = appId && serverUrl ? `https://${serverUrl}/oauth2/sessions/logout` : DEFAULT_OAUTH_LOGOUT_URL; | ||
|
||
return oauthUrl; | ||
}; | ||
|
||
export const getOAuthOrigin = () => { | ||
const { appId, serverUrl } = getServerInfo(); | ||
|
||
const oauthUrl = appId && serverUrl ? `https://${serverUrl}` : DEFAULT_OAUTH_ORIGIN_URL; | ||
|
||
return oauthUrl; | ||
}; | ||
|
||
export const isOAuth2Enabled = () => { | ||
const [OAuth2EnabledApps, OAuth2EnabledAppsInitialised] = Analytics.getGrowthbookFeatureValue({ | ||
featureFlag: 'hydra_be', | ||
}); | ||
const appId = WebSocketUtils.getAppId(); | ||
|
||
if (OAuth2EnabledAppsInitialised) { | ||
const FEHydraAppIds = OAuth2EnabledApps?.length | ||
? OAuth2EnabledApps[OAuth2EnabledApps.length - 1]?.enabled_for ?? [] | ||
: []; | ||
return FEHydraAppIds.includes(+appId); | ||
} | ||
|
||
return false; | ||
}; | ||
|
||
export const getLogoutHandler = onWSLogoutAndRedirect => { | ||
const isAuthEnabled = isOAuth2Enabled(); | ||
|
||
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}`); | ||
} | ||
} | ||
} | ||
}; | ||
|
||
window.addEventListener('message', onMessage); | ||
|
||
const oAuth2Logout = () => { | ||
if (!isAuthEnabled) { | ||
onWSLogoutAndRedirect(); | ||
return; | ||
} | ||
|
||
let iframe = document.getElementById('logout-iframe'); | ||
if (!iframe) { | ||
iframe = document.createElement('iframe'); | ||
iframe.id = 'logout-iframe'; | ||
iframe.style.display = 'none'; | ||
document.body.appendChild(iframe); | ||
|
||
setTimeout(() => { | ||
onWSLogoutAndRedirect(); | ||
}, LOGOUT_HANDLER_TIMEOUT); | ||
} | ||
|
||
iframe.src = getOAuthLogoutUrl(); | ||
}; | ||
|
||
return oAuth2Logout; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,10 @@ | ||
|
||
const Mock = require('mock-require'); | ||
Mock('../../auth', { | ||
isOAuth2Enabled: function() { | ||
return false | ||
} | ||
}); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
const Client = require('../client_base'); | ||
const setCurrencies = require('../currency_base').setCurrencies; | ||
const { api, expect, setURL } = require('../../__tests__/tests_common'); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import React from 'react'; | ||
import ReactDOM from 'react-dom'; | ||
import { isOAuth2Enabled } from '../../_common/auth'; | ||
|
||
const DerivIFrame = () => ( | ||
<iframe | ||
id='localstorage-sync' | ||
style={{ display: 'none', visibility: 'hidden' }} | ||
sandbox='allow-same-origin allow-scripts' | ||
/> | ||
); | ||
|
||
export const init = () => { | ||
const isAuthEnabled = isOAuth2Enabled(); | ||
|
||
if (!isAuthEnabled) ReactDOM.render(<DerivIFrame />, document.getElementById('deriv_iframe')); | ||
}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I moved the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. so we want to disable syncing in certain scenarios? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We only disable it when the Hydra authentication feature flag is enabled, which we turn on/off from Growthbook There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because one of our aim for this feature is to remove the use of Deriv iframe sync entirely and migrate these syncing logic into the Hydra service, which is on BE's side |
||
|
||
export default init; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[Q] whats appId check used here for?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Its just an extra check to ensure we have the app ID and server URL before returning the origin url