From 17e9dce7457cd766e0fab89e19f1c7229dc5fa55 Mon Sep 17 00:00:00 2001 From: RXRD Date: Thu, 10 Oct 2024 16:49:30 +0700 Subject: [PATCH 1/4] Update SharingSettings.tsx --- src/components/Settings/SharingSettings.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/components/Settings/SharingSettings.tsx b/src/components/Settings/SharingSettings.tsx index 509aeeb64..042e1ddd8 100644 --- a/src/components/Settings/SharingSettings.tsx +++ b/src/components/Settings/SharingSettings.tsx @@ -20,6 +20,7 @@ import { sha256 } from 'js-sha256'; import i18n from 'src/locale'; import { RootState } from 'src/reducers'; import { v4 as uuidv4 } from 'uuid'; +import { useUserHook } from 'src/hooks/use-user.hook'; const SharingSetting = () => { const styles = useStyles(); @@ -33,6 +34,8 @@ const SharingSetting = () => { message: '', }); + const { currentWallet } = useUserHook(); + const onChangeToken = (event: React.ChangeEvent) => { const input = event.target.value; From 6a981196bb5ed7676dc7641db793583050f92ba5 Mon Sep 17 00:00:00 2001 From: RXRD Date: Thu, 10 Oct 2024 22:04:39 +0700 Subject: [PATCH 2/4] fix --- pages/api/auth/[...nextauth].ts | 6 +- src/components/Login/Login.tsx | 7 + .../Login/render/PAT/LoginByPAT.style.ts | 38 ++++++ .../Login/render/PAT/LoginByPAT.tsx | 126 ++++++++++++++++++ .../render/SignInMethod/SigninMethod.tsx | 11 ++ src/components/Settings/SharingSettings.tsx | 44 ++---- src/lib/api/access-token.ts | 30 +++++ src/lib/api/auth-link.ts | 2 - 8 files changed, 224 insertions(+), 40 deletions(-) create mode 100644 src/components/Login/render/PAT/LoginByPAT.style.ts create mode 100644 src/components/Login/render/PAT/LoginByPAT.tsx create mode 100644 src/lib/api/access-token.ts diff --git a/pages/api/auth/[...nextauth].ts b/pages/api/auth/[...nextauth].ts index cafdf9731..88bf96f6c 100644 --- a/pages/api/auth/[...nextauth].ts +++ b/pages/api/auth/[...nextauth].ts @@ -128,7 +128,6 @@ const createOptions = (req: NextApiRequest) => ({ // e.g. domain, username, password, 2FA token, etc. credentials: { token: { label: 'Token', type: 'text' }, - rpcUrl: { label: 'rpc url', type: 'text' }, instanceURL: { label: 'Instance url', type: 'text' }, }, async authorize(credentials) { @@ -137,10 +136,7 @@ const createOptions = (req: NextApiRequest) => ({ // Initialize instance api url initialize({ apiURL: credentials.instanceURL }); - const data = await AuthLinkAPI.loginWithAccessToken( - credentials.token, - credentials.rpcUrl, - ); + const data = await AuthLinkAPI.loginWithAccessToken(credentials.token); if (!data?.token?.accessToken) throw Error('Failed to authorize user!'); diff --git a/src/components/Login/Login.tsx b/src/components/Login/Login.tsx index f3da341c9..85da63381 100644 --- a/src/components/Login/Login.tsx +++ b/src/components/Login/Login.tsx @@ -18,6 +18,7 @@ import { Accounts } from './render/Accounts'; import CreateAccounts from './render/CreateAccounts/CreateAccounts'; import LoginByEmail from './render/Email/LoginByEmail'; import { Options } from './render/Options'; +import LoginByPAT from './render/PAT/LoginByPAT'; import { Profile } from './render/Profile'; import SigninMethod from './render/SignInMethod/SigninMethod'; @@ -345,6 +346,12 @@ export const Login: React.FC = props => { element={} /> + } + /> + + createStyles({ + root: { + position: 'relative', + maxHeight: 'fit-content', + maxWidth: 508, + background: '#FFFFFF', + borderRadius: 10, + padding: 40, + boxShadow: '0px 2px 10px rgba(0, 0, 0, 0.05)', + display: 'flex', + flexDirection: 'column', + gap: 24, + '& .MuiFormControl-root': { + marginBottom: 0, + }, + }, + title: { + fontSize: 18, + fontWeight: 'bold', + color: 'black', + textAlign: 'center', + }, + subtitle: { + fontSize: 14, + fontWeight: 'normal', + color: 'black', + textAlign: 'center', + }, + actionWrapper: { + display: 'flex', + flexDirection: 'row', + gap: 24, + }, + }), +); diff --git a/src/components/Login/render/PAT/LoginByPAT.tsx b/src/components/Login/render/PAT/LoginByPAT.tsx new file mode 100644 index 000000000..9d8ccec0d --- /dev/null +++ b/src/components/Login/render/PAT/LoginByPAT.tsx @@ -0,0 +1,126 @@ +import { useState, useEffect } from 'react'; +import { useCookies } from 'react-cookie'; +import { useNavigate } from 'react-router'; + +import { signIn } from 'next-auth/react'; +import getConfig from 'next/config'; +import { useRouter } from 'next/router'; + +import { Button, TextField, Typography } from '@material-ui/core'; + +import { useStyles } from './LoginByPAT.style'; + +import { COOKIE_INSTANCE_URL } from 'components/SelectServer'; +import SelectServer from 'src/components/SelectServer'; +import { useAuthLinkHook } from 'src/hooks/auth-link.hook'; +import { useAlertHook } from 'src/hooks/use-alert.hook'; +import { ServerListProps } from 'src/interfaces/server-list'; +import i18n from 'src/locale'; +import validator from 'validator'; + +type LoginByPATProps = { + onNext: ( + successCallback: () => void, + failedCallback: () => void, + email: string, + ) => Promise; +}; + +const LoginByPAT = ({ onNext }: LoginByPATProps) => { + const styles = useStyles(); + const router = useRouter(); + const { publicRuntimeConfig } = getConfig(); + const { showAlert } = useAlertHook(); + + const { requestLink } = useAuthLinkHook(); + const [cookies] = useCookies([COOKIE_INSTANCE_URL]); + + const [token, setToken] = useState(''); + const [error, setError] = useState({ + isError: false, + message: '', + }); + const [, setDisableSignIn] = useState(false); + + const handleChange = (event: React.ChangeEvent) => { + const input = event.target.value; + setToken(input); + }; + + const navigate = useNavigate(); + + const handleNext = () => { + signIn('tokenCredentials', { + token, + instanceURL: cookies[COOKIE_INSTANCE_URL], + redirect: false, + callbackUrl: publicRuntimeConfig.appAuthURL, + }).then(response => { + if (response.ok) { + router.reload(); + router.push('/'); + } + + if (response.error) { + showAlert({ + message: token + ? i18n.t('Login.Alert.Invalid_OTP') + : i18n.t('Login.Alert.Message'), + severity: 'error', + title: i18n.t('Login.Alert.Title'), + }); + setDisableSignIn(false); + } + }); + }; + + const handleBack = () => { + navigate('/'); + }; + + const handleSwitchInstance = ( + server: ServerListProps, + callback?: () => void, + ) => { + callback && callback(); + }; + + return ( +
+
+ + {i18n.t('Login.Email.LoginByEmail.Title')} + + + {i18n.t('Login.Email.LoginByEmail.Subtitle')} + +
+ + +
+ + +
+
+ ); +}; + +export default LoginByPAT; diff --git a/src/components/Login/render/SignInMethod/SigninMethod.tsx b/src/components/Login/render/SignInMethod/SigninMethod.tsx index bae4d3b73..e0648f306 100644 --- a/src/components/Login/render/SignInMethod/SigninMethod.tsx +++ b/src/components/Login/render/SignInMethod/SigninMethod.tsx @@ -20,6 +20,8 @@ export default function SigninMethod({ const handleSelected = ({ method }: { method: string }) => { if (method === 'web2') { navigate('/email'); + } else if (method === 'pat') { + navigate('/pat'); } else { navigate('/options'); } @@ -87,6 +89,15 @@ export default function SigninMethod({ disabled={disableSignIn} tooltip={i18n.t('Sign_In.Email.tooltip')} /> +
or
+ } + onClick={() => handleSelected({ method: 'pat' })} + disabled={disableSignIn} + tooltip={i18n.t('Sign_In.Token.tooltip')} + /> diff --git a/src/components/Settings/SharingSettings.tsx b/src/components/Settings/SharingSettings.tsx index 042e1ddd8..778fc3ebb 100644 --- a/src/components/Settings/SharingSettings.tsx +++ b/src/components/Settings/SharingSettings.tsx @@ -13,14 +13,17 @@ import { Typography, } from '@material-ui/core'; +import { ApiPromise, WsProvider } from '@polkadot/api'; + import { Modal } from '../atoms/Modal'; import { useStyles } from './Settings.styles'; import { sha256 } from 'js-sha256'; +import { useUserHook } from 'src/hooks/use-user.hook'; +import * as AccessTokenAPI from 'src/lib/api/access-token'; import i18n from 'src/locale'; import { RootState } from 'src/reducers'; import { v4 as uuidv4 } from 'uuid'; -import { useUserHook } from 'src/hooks/use-user.hook'; const SharingSetting = () => { const styles = useStyles(); @@ -45,7 +48,7 @@ const SharingSetting = () => { setToken(event.target.value); }; - const onClickAddToken = () => { + const onClickAddToken = async () => { const token = uuidv4(); const tokenHash = sha256(token); const first = token.slice(0, 4); @@ -53,7 +56,12 @@ const SharingSetting = () => { const replacement = 'xxxx-xxxx-xxxx-xxxx-xxxxxxxx'; const disguise = first + replacement + second; console.log(tokenHash, disguise); - setModalOpen(true); + try { + await AccessTokenAPI.postToken(tokenHash, disguise); + setModalOpen(true); + } catch (error) { + console.error(error); + } // TODO create access token on blockchain // await createAccessToken(hash, wallet) @@ -84,36 +92,6 @@ const SharingSetting = () => { Token is {tokenValue} - Input Code Here -
- <> - - - -