Skip to content

Commit

Permalink
chore: implement TOTP flow
Browse files Browse the repository at this point in the history
  • Loading branch information
solufa committed Dec 25, 2024
1 parent 81dda4c commit 7c5411b
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 10 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ You can check the emails sent by Magnito with Inbucket.
- Sign in with your email address and password.
- Sign in with Google / Apple / Amazon / Facebook emulators.
- Support MFA with TOTP.
- Forgot Password
Expand Down
12 changes: 2 additions & 10 deletions client/layouts/BasicHeader/BasicHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import { signOut } from 'aws-amplify/auth';
import { APP_NAME } from 'common/constants';
import type { UserEntity } from 'common/types/user';
import { Modal, ModalBody, ModalFooter, ModalHeader } from 'components/Modal/Modal';
import { Spacer } from 'components/Spacer';
import type { ReactNode } from 'react';
import { useEffect, useState } from 'react';
import { APP_VERSION } from 'utils/envValues';
import styles from './BasicHeader.module.css';
import { YourProfile } from './YourProfile';

const Menu = ({
open,
Expand Down Expand Up @@ -58,15 +58,7 @@ export const BasicHeader = (props: { user: UserEntity }) => {
<MenuItem onClick={signOut}>ログアウト</MenuItem>
</Menu>
</div>
<Modal open={openProfile} onClose={() => setOpenProfile(false)}>
<ModalHeader text="プロフィール" />
<ModalBody>
<div>ユーザー名: {props.user.name}</div>
<Spacer axis="y" size={8} />
<div>メールアドレス: {props.user.email}</div>
</ModalBody>
<ModalFooter cancelText="閉じる" cancel={() => setOpenProfile(false)} />
</Modal>
{openProfile && <YourProfile user={props.user} onClose={() => setOpenProfile(false)} />}
<Modal open={openPassword} onClose={() => setOpenPassword(false)}>
<ModalHeader text="パスワードの変更" />
<ModalBody>
Expand Down
75 changes: 75 additions & 0 deletions client/layouts/BasicHeader/YourProfile.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { Button, TextField, View } from '@aws-amplify/ui-react';
import {
fetchMFAPreference,
setUpTOTP,
updateMFAPreference,
verifyTOTPSetup,
} from 'aws-amplify/auth';
import { APP_NAME } from 'common/constants';
import type { UserEntity } from 'common/types/user';
import { Modal, ModalBody, ModalFooter, ModalHeader } from 'components/Modal/Modal';
import { Spacer } from 'components/Spacer';
import { useEffect, useState } from 'react';

export const YourProfile = (props: { user: UserEntity; onClose: () => void }) => {
const [enabledTotp, setEnabledTotp] = useState<boolean>();
const [qrCodeUrl, setQrCodeUrl] = useState('');
const [totpCode, setTotpCode] = useState('');
const enableTOTP = async () => {
const totpSetupDetails = await setUpTOTP();
const setupUri = totpSetupDetails.getSetupUri(APP_NAME);

setQrCodeUrl(setupUri.toString());
};
const verifyTOTP = async () => {
await verifyTOTPSetup({ code: totpCode });
await updateMFAPreference({ totp: 'PREFERRED' });
alert('二要素認証が有効になりました。');
setQrCodeUrl('');
};

useEffect(() => {
fetchMFAPreference().then((res) => {
setEnabledTotp(res.preferred === 'TOTP');
});
}, []);

return (
<Modal open onClose={props.onClose}>
<ModalHeader text="プロフィール" />
<ModalBody>
<div>ユーザー名: {props.user.name}</div>
<Spacer axis="y" size={8} />
<div>メールアドレス: {props.user.email}</div>
<Spacer axis="y" size={8} />
{enabledTotp ? (
<div>二要素認証: 有効</div>
) : qrCodeUrl ? (
<View>
<p>認証アプリでこのQRコードをスキャンしてください</p>
<img
src={`https://api.qrserver.com/v1/create-qr-code/?data=${encodeURIComponent(
qrCodeUrl,
)}`}
alt="TOTP QR Code"
style={{ padding: 16, width: 150 }}
/>
<TextField
label="ワンタイムトークンコードを入力"
placeholder="123456"
value={totpCode}
onChange={(e) => setTotpCode(e.target.value)}
/>
<Spacer axis="y" size={8} />
<Button onClick={verifyTOTP}>送信</Button>
</View>
) : (
<Button size="small" onClick={enableTOTP}>
二要素認証有効化
</Button>
)}
</ModalBody>
<ModalFooter cancelText="Close" cancel={props.onClose} />
</Modal>
);
};

0 comments on commit 7c5411b

Please sign in to comment.