Skip to content

Commit

Permalink
feat: add new login method (#1957)
Browse files Browse the repository at this point in the history
* Update SharingSettings.tsx

* fix

* fix

* fix
  • Loading branch information
RiXelanya authored Oct 10, 2024
1 parent 1c939e6 commit c813b68
Show file tree
Hide file tree
Showing 8 changed files with 217 additions and 53 deletions.
6 changes: 1 addition & 5 deletions pages/api/auth/[...nextauth].ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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!');

Expand Down
7 changes: 7 additions & 0 deletions src/components/Login/Login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -345,6 +346,12 @@ export const Login: React.FC<LoginProps> = props => {
element={<LoginByEmail onNext={checkEmailRegistered} />}
/>

<Route
index={false}
path="/pat"
element={<LoginByPAT onNext={checkEmailRegistered} />}
/>

<Route
index={false}
path="/createAccounts"
Expand Down
38 changes: 38 additions & 0 deletions src/components/Login/render/PAT/LoginByPAT.style.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';

export const useStyles = makeStyles((theme: Theme) =>
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,
},
}),
);
122 changes: 122 additions & 0 deletions src/components/Login/render/PAT/LoginByPAT.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import { useState } 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 { useAlertHook } from 'src/hooks/use-alert.hook';
import { ServerListProps } from 'src/interfaces/server-list';
import i18n from 'src/locale';

type LoginByPATProps = {
onNext: (
successCallback: () => void,
failedCallback: () => void,
email: string,
) => Promise<void>;
};

const LoginByPAT = ({ onNext }: LoginByPATProps) => {
const styles = useStyles();
const router = useRouter();
const { publicRuntimeConfig } = getConfig();
const { showAlert } = useAlertHook();
const [cookies] = useCookies([COOKIE_INSTANCE_URL]);

const [token, setToken] = useState('');
const [error] = useState({
isError: false,
message: '',
});
const [, setDisableSignIn] = useState<boolean>(false);

const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
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 (
<div className={styles.root}>
<div>
<Typography className={styles.title}>
{i18n.t('Login.Email.LoginByEmail.Title')}
</Typography>
<Typography className={styles.subtitle}>
{i18n.t('Login.Email.LoginByEmail.Subtitle')}
</Typography>
</div>
<TextField
fullWidth
id="user-email-input"
label="Token"
variant="outlined"
placeholder={i18n.t('Login.Email.LoginByEmail.Email_Placeholder')}
value={token}
onChange={handleChange}
error={error.isError}
helperText={error.isError ? error.message : ''}
/>
<SelectServer page="login" onSwitchInstance={handleSwitchInstance} />
<div className={styles.actionWrapper}>
<Button variant="outlined" color="primary" onClick={handleBack}>
{i18n.t('Login.Email.LoginByEmail.Back')}
</Button>
<Button
variant="contained"
color="primary"
disabled={!token.length || error.isError}
onClick={handleNext}>
{i18n.t('Login.Email.LoginByEmail.Next')}
</Button>
</div>
</div>
);
};

export default LoginByPAT;
11 changes: 11 additions & 0 deletions src/components/Login/render/SignInMethod/SigninMethod.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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');
}
Expand Down Expand Up @@ -87,6 +89,15 @@ export default function SigninMethod({
disabled={disableSignIn}
tooltip={i18n.t('Sign_In.Email.tooltip')}
/>
<div className={styles.textOr}>or</div>
<CardSign
title={i18n.t('Sign_In.Token.title')}
desc={i18n.t('Sign_In.Token.desc')}
image={<LoginWeb2 />}
onClick={() => handleSelected({ method: 'pat' })}
disabled={disableSignIn}
tooltip={i18n.t('Sign_In.Token.tooltip')}
/>
</div>
</div>
</>
Expand Down
54 changes: 8 additions & 46 deletions src/components/Settings/SharingSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { useSelector } from 'react-redux';

import {
Button,
TextField,
Paper,
Grid,
CircularProgress,
Expand All @@ -17,6 +16,7 @@ import { Modal } from '../atoms/Modal';
import { useStyles } from './Settings.styles';

import { sha256 } from 'js-sha256';
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';
Expand All @@ -28,29 +28,21 @@ const SharingSetting = () => {
);
const [tokenValue, setToken] = useState('');
const [modalOpen, setModalOpen] = useState(false);
const [error, setError] = useState({
isError: false,
message: '',
});

const onChangeToken = (event: React.ChangeEvent<HTMLInputElement>) => {
const input = event.target.value;

if (!input.length) {
setError({ isError: false, message: '' });
}
setToken(event.target.value);
};

const onClickAddToken = () => {
const onClickAddToken = async () => {
const token = uuidv4();
const tokenHash = sha256(token);
const first = token.slice(0, 4);
const second = token.slice(-4);
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)
Expand Down Expand Up @@ -81,36 +73,6 @@ const SharingSetting = () => {
Token is {tokenValue}
</Typography>
</Modal>
<Typography className={styles.subtitle}>Input Code Here</Typography>
<div
className={styles.option}
style={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
}}>
<>
<TextField
variant="outlined"
fullWidth
label={i18n.t('Setting.List_Menu.Token_Code')}
placeholder={i18n.t('Setting.List_Menu.Token_Code')}
value={tokenValue}
style={{ marginBottom: 'unset' }}
onChange={onChangeToken}
error={error.isError}
helperText={error.isError ? error.message : ''}
/>
<Button
size="small"
variant="contained"
color="primary"
style={{ marginLeft: '24px', marginRight: '17px' }}
onClick={onClickAddToken}>
Add
</Button>
</>
</div>
<div>
<Button
size="medium"
Expand Down
30 changes: 30 additions & 0 deletions src/lib/api/access-token.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import MyriadAPI from './base';

export const postToken = async (
hash: string,
disguise: string,
): Promise<void> => {
try {
await MyriadAPI().request({
url: `/user/personal-access-tokens`,
method: 'POST',
data: {
token: disguise,
hash: hash,
},
});
} catch (e) {
console.error(e);
}
};

export const getToken = async () => {
try {
await MyriadAPI().request({
url: `/user/personal-access-tokens`,
method: 'GET',
});
} catch (e) {
console.error(e);
}
};
2 changes: 0 additions & 2 deletions src/lib/api/auth-link.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,12 @@ export const loginWithLink = async (

export const loginWithAccessToken = async (
token: string,
rpcUrl: string,
): Promise<LoginResponseProps> => {
const { data } = await MyriadAPI().request({
url: '/authentication/login/pat',
method: 'POST',
data: {
token,
rpcUrl,
},
headers: {
'Content-Type': 'application/json',
Expand Down

0 comments on commit c813b68

Please sign in to comment.