155 lines
3.9 KiB
TypeScript
155 lines
3.9 KiB
TypeScript
import { useCallback, useEffect, useState } from 'react';
|
|
import { generateNonce, SiweMessage } from 'siwe';
|
|
import axios from 'axios';
|
|
import { useNavigate } from 'react-router-dom';
|
|
|
|
import { Box, Modal } from '@mui/material';
|
|
|
|
import { BASE_URL, VITE_WALLET_IFRAME_URL } from 'utils/constants';
|
|
|
|
const axiosInstance = axios.create({
|
|
baseURL: BASE_URL,
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'Access-Control-Allow-Origin': '*',
|
|
},
|
|
withCredentials: true,
|
|
});
|
|
|
|
const AutoSignInIFrameModal = () => {
|
|
const navigate = useNavigate();
|
|
|
|
const [accountAddress, setAccountAddress] = useState();
|
|
|
|
useEffect(() => {
|
|
const handleSignInResponse = async (event: MessageEvent) => {
|
|
if (event.origin !== VITE_WALLET_IFRAME_URL) return;
|
|
|
|
if (event.data.type === 'SIGN_IN_RESPONSE') {
|
|
try {
|
|
const { success } = (
|
|
await axiosInstance.post('/auth/validate', {
|
|
message: event.data.data.message,
|
|
signature: event.data.data.signature,
|
|
})
|
|
).data;
|
|
|
|
if (success === true) {
|
|
navigate('/');
|
|
}
|
|
} catch (error) {
|
|
console.error('Error signing in:', error);
|
|
}
|
|
}
|
|
};
|
|
|
|
window.addEventListener('message', handleSignInResponse);
|
|
|
|
return () => {
|
|
window.removeEventListener('message', handleSignInResponse);
|
|
};
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
const initiateAutoSignIn = async () => {
|
|
if (!accountAddress) return;
|
|
|
|
const iframe = document.getElementById(
|
|
'autoSignInFrame',
|
|
) as HTMLIFrameElement;
|
|
|
|
if (!iframe.contentWindow) {
|
|
console.error('Iframe not found or not loaded');
|
|
return;
|
|
}
|
|
|
|
const message = new SiweMessage({
|
|
version: '1',
|
|
domain: window.location.host,
|
|
uri: window.location.origin,
|
|
chainId: 1,
|
|
address: accountAddress,
|
|
nonce: generateNonce(),
|
|
// Human-readable ASCII assertion that the user will sign, and it must not contain `\n`.
|
|
statement: 'Sign in With Ethereum.',
|
|
}).prepareMessage();
|
|
|
|
iframe.contentWindow.postMessage(
|
|
{
|
|
type: 'AUTO_SIGN_IN',
|
|
chainId: '1',
|
|
message,
|
|
},
|
|
VITE_WALLET_IFRAME_URL,
|
|
);
|
|
};
|
|
|
|
initiateAutoSignIn();
|
|
}, [accountAddress]);
|
|
|
|
useEffect(() => {
|
|
const handleAccountsDataResponse = async (event: MessageEvent) => {
|
|
if (event.origin !== VITE_WALLET_IFRAME_URL) return;
|
|
|
|
if (event.data.type === 'WALLET_ACCOUNTS_DATA') {
|
|
setAccountAddress(event.data.data[0].address);
|
|
}
|
|
};
|
|
|
|
window.addEventListener('message', handleAccountsDataResponse);
|
|
|
|
return () => {
|
|
window.removeEventListener('message', handleAccountsDataResponse);
|
|
};
|
|
}, []);
|
|
|
|
const getAddressFromWallet = useCallback(() => {
|
|
const iframe = document.getElementById(
|
|
'autoSignInFrame',
|
|
) as HTMLIFrameElement;
|
|
|
|
if (!iframe.contentWindow) {
|
|
console.error('Iframe not found or not loaded');
|
|
return;
|
|
}
|
|
|
|
iframe.contentWindow.postMessage(
|
|
{
|
|
type: 'REQUEST_CREATE_OR_GET_ACCOUNTS',
|
|
chainId: '1',
|
|
},
|
|
VITE_WALLET_IFRAME_URL,
|
|
);
|
|
}, []);
|
|
|
|
return (
|
|
<Modal open={true} disableEscapeKeyDown keepMounted>
|
|
<Box
|
|
sx={{
|
|
position: 'absolute',
|
|
top: '50%',
|
|
left: '50%',
|
|
transform: 'translate(-50%, -50%)',
|
|
width: '90%',
|
|
maxWidth: '1200px',
|
|
height: '600px',
|
|
maxHeight: '80vh',
|
|
overflow: 'auto',
|
|
outline: 'none',
|
|
}}
|
|
>
|
|
<iframe
|
|
onLoad={getAddressFromWallet}
|
|
id="autoSignInFrame"
|
|
src={`${VITE_WALLET_IFRAME_URL}/auto-sign-in`}
|
|
width="100%"
|
|
height="100%"
|
|
sandbox="allow-scripts allow-same-origin"
|
|
></iframe>
|
|
</Box>
|
|
</Modal>
|
|
);
|
|
};
|
|
|
|
export default AutoSignInIFrameModal;
|