-
Notifications
You must be signed in to change notification settings - Fork 27
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
13 changed files
with
557 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import KyberOauth2 from '@kybernetwork/oauth2' | ||
import { useEffect } from 'react' | ||
|
||
import { ENV_KEY } from 'constants/env' | ||
import useParsedQueryString from 'hooks/useParsedQueryString' | ||
import { PageContainer } from 'pages/Oauth/styled' | ||
|
||
function Page() { | ||
const { consent_challenge } = useParsedQueryString<{ consent_challenge: string }>() | ||
|
||
useEffect(() => { | ||
if (!consent_challenge) return | ||
KyberOauth2.initialize({ mode: ENV_KEY }) | ||
KyberOauth2.oauthUi | ||
.getFlowConsent(consent_challenge) | ||
.then(data => { | ||
console.debug('resp consent', data) | ||
}) | ||
.catch(err => { | ||
console.debug('err consent', err) | ||
}) | ||
}, [consent_challenge]) | ||
|
||
return <PageContainer msg={'Checking data...'} /> | ||
} | ||
|
||
export default Page |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
import KyberOauth2, { LoginFlow, LoginMethod } from '@kybernetwork/oauth2' | ||
import { useCallback, useEffect, useRef, useState } from 'react' | ||
|
||
import Loader from 'components/Loader' | ||
import { didUserReject } from 'constants/connectors/utils' | ||
import { ENV_KEY } from 'constants/env' | ||
import { useActiveWeb3React, useWeb3React } from 'hooks' | ||
import useParsedQueryString from 'hooks/useParsedQueryString' | ||
import { Col, Container, KyberLogo, TextDesc } from 'pages/Oauth/styled' | ||
import getShortenAddress from 'utils/getShortenAddress' | ||
import { queryStringToObject } from 'utils/string' | ||
import { formatSignature } from 'utils/transaction' | ||
|
||
import AuthForm from './components/AuthForm' | ||
import { BUTTON_IDS } from './constants/index' | ||
import { createSignMessage, getSupportLoginMethods } from './utils' | ||
|
||
const getErrorMsg = (error: any) => { | ||
const data = error?.response?.data | ||
const isExpired = data?.error?.id === 'self_service_flow_expired' | ||
if (isExpired) | ||
return ( | ||
<span> | ||
Time to sign-in is Expired, please{' '} | ||
<a href={queryStringToObject(window.location.search)?.back_uri + ''}>go back</a> and try again. | ||
Check warning Code scanning / CodeQL Client-side cross-site scripting Medium
Cross-site scripting vulnerability due to
user-provided value Error loading related location Loading Check warning Code scanning / CodeQL Client-side URL redirect Medium
Untrusted URL redirection depends on a
user-provided value Error loading related location Loading |
||
</span> | ||
) | ||
return data?.ui?.messages?.[0]?.text || data?.error?.reason || data?.error?.message || error?.message || error + '' | ||
} | ||
|
||
function Login() { | ||
const { account: address, chainId } = useActiveWeb3React() | ||
const { library: provider } = useWeb3React() | ||
|
||
const [processingSignEth, setProcessingSign] = useState(false) | ||
const [authFormConfig, setAuthFormConfig] = useState<LoginFlow>() | ||
const [error, setError] = useState('') | ||
const [autoLogin, setAutoLogin] = useState(false) // not waiting for click btn | ||
|
||
const { wallet_address } = useParsedQueryString<{ wallet_address: string }>() | ||
|
||
const loginMethods = getSupportLoginMethods(authFormConfig) | ||
const isSignInEth = loginMethods.includes(LoginMethod.ETH) | ||
const isMismatchEthAddress = | ||
!loginMethods.includes(LoginMethod.GOOGLE) && | ||
isSignInEth && | ||
wallet_address && | ||
address && | ||
wallet_address?.toLowerCase() !== address?.toLowerCase() | ||
|
||
const connectingWallet = useRef(false) | ||
|
||
const signInWithEth = useCallback(async () => { | ||
try { | ||
const siweConfig = authFormConfig?.oauth_client?.metadata?.siwe_config | ||
if (isMismatchEthAddress || !siweConfig || connectingWallet.current || !provider || !address || !chainId) { | ||
return | ||
} | ||
setProcessingSign(true) | ||
const { ui, challenge, issued_at } = authFormConfig | ||
connectingWallet.current = true | ||
const csrf = ui.nodes.find(e => e.attributes.name === 'csrf_token')?.attributes?.value ?? '' | ||
const message = createSignMessage({ | ||
address, | ||
chainId, | ||
nonce: challenge, | ||
issuedAt: issued_at, | ||
...siweConfig, | ||
}) | ||
|
||
const signature = await provider.getSigner().signMessage(message) | ||
const resp = await KyberOauth2.oauthUi.loginEthereum({ | ||
address, | ||
signature: formatSignature(signature), | ||
csrf, | ||
chainId, | ||
}) | ||
|
||
if (resp) { | ||
connectingWallet.current = false | ||
setProcessingSign(false) | ||
} | ||
} catch (error: any) { | ||
if (!didUserReject(error)) { | ||
setError(getErrorMsg(error)) | ||
} | ||
console.error('signInWithEthereum err', error) | ||
connectingWallet.current = false | ||
setProcessingSign(false) | ||
} | ||
}, [address, provider, authFormConfig, chainId, isMismatchEthAddress]) | ||
|
||
useEffect(() => { | ||
const getFlowLogin = async () => { | ||
try { | ||
KyberOauth2.initialize({ mode: ENV_KEY }) | ||
const loginFlow = await KyberOauth2.oauthUi.getFlowLogin() | ||
if (!loginFlow) return | ||
setAuthFormConfig(loginFlow) | ||
|
||
const { client_id } = loginFlow.oauth_client | ||
const loginMethods = getSupportLoginMethods(loginFlow) | ||
|
||
let autoLogin = false | ||
const isIncludeGoogle = loginMethods.includes(LoginMethod.GOOGLE) | ||
if (loginMethods.length === 1) { | ||
if (loginMethods.includes(LoginMethod.ANONYMOUS)) { | ||
throw new Error('Not found login method for this app') | ||
} | ||
if (isIncludeGoogle) { | ||
autoLogin = true | ||
} | ||
} | ||
// todo | ||
if (loginMethods.includes(LoginMethod.ETH) && !isIncludeGoogle) { | ||
setTimeout(() => document.getElementById(BUTTON_IDS.LOGIN_ETH)?.click(), 200) | ||
} | ||
setAutoLogin(autoLogin) | ||
KyberOauth2.initialize({ clientId: client_id, mode: ENV_KEY }) | ||
|
||
if (autoLogin) setTimeout(() => document.getElementById(BUTTON_IDS.LOGIN_GOOGLE)?.click(), 200) | ||
} catch (error: any) { | ||
const { error_description } = queryStringToObject(window.location.search) | ||
setError(error_description || getErrorMsg(error)) | ||
} | ||
} | ||
getFlowLogin() | ||
}, []) | ||
|
||
const appName = authFormConfig?.oauth_client?.client_name || authFormConfig?.oauth_client?.client_id | ||
|
||
const renderEthMsg = () => | ||
isMismatchEthAddress ? ( | ||
<TextDesc> | ||
Your address is mismatched. The expected address is {getShortenAddress(wallet_address)}, but the address | ||
provided is {getShortenAddress(address)}. Please change your wallet address accordingly. | ||
</TextDesc> | ||
) : ( | ||
address && ( | ||
<TextDesc> | ||
To get started, please sign-in to verify your ownership of this wallet address {getShortenAddress(address)} | ||
</TextDesc> | ||
) | ||
) | ||
|
||
return ( | ||
<Container> | ||
<Col> | ||
<KyberLogo /> | ||
{error ? ( | ||
<TextDesc>{error}</TextDesc> | ||
) : autoLogin ? ( | ||
<TextDesc style={{ display: 'flex', alignItems: 'center', gap: '10px' }}> | ||
<Loader /> Checking data ... | ||
</TextDesc> | ||
) : isSignInEth && address ? ( | ||
renderEthMsg() | ||
) : ( | ||
appName && <TextDesc>Please sign in to continue with {appName}</TextDesc> | ||
)} | ||
<AuthForm | ||
formConfig={authFormConfig} | ||
autoLogin={autoLogin} | ||
signInWithEth={signInWithEth} | ||
processingSignEth={processingSignEth} | ||
disableEth={!!isMismatchEthAddress} | ||
/> | ||
</Col> | ||
</Container> | ||
) | ||
} | ||
|
||
export default Login |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import KyberOauth2 from '@kybernetwork/oauth2' | ||
import { useEffect } from 'react' | ||
|
||
import { ENV_KEY } from 'constants/env' | ||
import useParsedQueryString from 'hooks/useParsedQueryString' | ||
import { PageContainer } from 'pages/Oauth/styled' | ||
|
||
function Logout() { | ||
const { logout_challenge } = useParsedQueryString<{ logout_challenge: string }>() | ||
|
||
useEffect(() => { | ||
if (!logout_challenge) return | ||
KyberOauth2.initialize({ mode: ENV_KEY }) | ||
KyberOauth2.oauthUi | ||
.acceptLogout(logout_challenge) | ||
.then(data => { | ||
console.debug('logout resp', data) | ||
}) | ||
.catch(err => { | ||
console.debug('err logout', err) | ||
}) | ||
}, [logout_challenge]) | ||
|
||
return <PageContainer msg={'Logging out...'} /> | ||
} | ||
|
||
export default Logout |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import { LoginFlowUiNode } from '@kybernetwork/oauth2' | ||
import React from 'react' | ||
|
||
import { ButtonOutlined, ButtonPrimary } from 'components/Button' | ||
|
||
import { BUTTON_IDS } from '../../constants/index' | ||
|
||
interface AuthFormFieldProps extends React.InputHTMLAttributes<HTMLInputElement> { | ||
field: LoginFlowUiNode | ||
outline?: boolean | ||
} | ||
|
||
const AuthFormField: React.FC<AuthFormFieldProps> = ({ field, outline }) => { | ||
const attributes = field.attributes | ||
if (field.group === 'oidc') { | ||
const props = { | ||
height: '36px', | ||
id: BUTTON_IDS.LOGIN_GOOGLE, | ||
type: 'submit', | ||
value: attributes.value, | ||
name: attributes.name, | ||
children: <>Sign-In with Google</>, | ||
} | ||
return React.createElement(outline ? ButtonOutlined : ButtonPrimary, props) | ||
} | ||
return null | ||
} | ||
export default AuthFormField |
20 changes: 20 additions & 0 deletions
20
src/pages/Oauth/components/AuthForm/AuthFormFieldMessage.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import { Text } from 'rebass' | ||
|
||
import useTheme from 'hooks/useTheme' | ||
|
||
const AuthFormFieldMessage: React.FC<{ messages?: { type: string; text: string }[] }> = ({ messages }) => { | ||
const theme = useTheme() | ||
if (!messages?.length) return null | ||
|
||
const messageList: JSX.Element[] = messages.map((value, index) => { | ||
return ( | ||
<Text as="label" key={index} color={value.type === 'warn' ? theme.warning : theme.red}> | ||
{value.text} | ||
</Text> | ||
) | ||
}) | ||
|
||
return <div className="form-text">{messageList}</div> | ||
} | ||
|
||
export default AuthFormFieldMessage |
Oops, something went wrong.