Persist subscriber ID in local storage (#26)
Part of [laconicd testnet validator enrollment](https://www.notion.so/laconicd-testnet-validator-enrollment-6fc1d3cafcc64fef8c5ed3affa27c675) - Disable nitro key sign button if subscribe ID does not exist Co-authored-by: Shreerang Kale <shreerangkale@gmail.com> Reviewed-on: #26
This commit is contained in:
parent
aa9aed89f2
commit
fc1c8df06b
@ -12,6 +12,7 @@
|
||||
}
|
||||
},
|
||||
"rules": {
|
||||
"indent": ["error", 2, { "SwitchCase": 1 }]
|
||||
"indent": ["error", 2, { "SwitchCase": 1 }],
|
||||
"semi": ["error", "always"]
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import { Link, useLocation } from 'react-router-dom';
|
||||
import { AppBar, Toolbar, Avatar, Box, IconButton } from '@mui/material';
|
||||
|
||||
const Header: React.FC = () => {
|
||||
const location = useLocation()
|
||||
const location = useLocation();
|
||||
|
||||
return (
|
||||
<AppBar position="static" color="inherit">
|
||||
|
@ -14,16 +14,16 @@ const SelectRoleCard = ({ handleAccept, handleRoleChange }: { handleAccept: () =
|
||||
const [checked, setChecked] = useState(false);
|
||||
const [isHidden, setIsHidden] = useState(false);
|
||||
|
||||
const [isDialogOpen, setisDialogOpen] = useState(false)
|
||||
const [isDialogOpen, setisDialogOpen] = useState(false);
|
||||
|
||||
const handleCheckboxChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setChecked(event.target.checked);
|
||||
};
|
||||
|
||||
const handleContinue = () => {
|
||||
handleAccept()
|
||||
setIsHidden(true)
|
||||
}
|
||||
handleAccept();
|
||||
setIsHidden(true);
|
||||
};
|
||||
|
||||
const handleRadioChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setSelectedRole(event.target.value as Role);
|
||||
|
@ -4,7 +4,7 @@ import { Document, Page, pdfjs } from 'react-pdf';
|
||||
import { Typography } from '@mui/material';
|
||||
|
||||
// https://github.com/wojtekmaj/react-pdf?tab=readme-ov-file#copy-worker-to-public-directory
|
||||
pdfjs.GlobalWorkerOptions.workerSrc = process.env.PUBLIC_URL + '/pdf.worker.min.mjs'
|
||||
pdfjs.GlobalWorkerOptions.workerSrc = process.env.PUBLIC_URL + '/pdf.worker.min.mjs';
|
||||
|
||||
const TermsAndConditionsBox = ({height}: {height: string}) => {
|
||||
const [numPages, setNumPages] = useState<number>();
|
||||
|
@ -1,5 +1,7 @@
|
||||
export const WALLET_DISCLAIMER_MSG = 'You are connecting to an experimental wallet! It is not secure. Do not use it elsewhere and/or for managing real assets.'
|
||||
export const WALLET_DISCLAIMER_MSG = 'You are connecting to an experimental wallet! It is not secure. Do not use it elsewhere and/or for managing real assets.';
|
||||
|
||||
export const REDIRECT_EMAIL_MSG = 'Close this tab and the confirmation link in your email will bring you back to the onboarding app.'
|
||||
export const REDIRECT_EMAIL_MSG = 'Close this tab and the confirmation link in your email will bring you back to the onboarding app.';
|
||||
|
||||
export const ENABLE_KYC = false;
|
||||
|
||||
export const SUBSCRIBER_ID_HASH_KEY = 'subscriberIdHash';
|
||||
|
@ -1,8 +1,8 @@
|
||||
import React from 'react'
|
||||
import React from 'react';
|
||||
|
||||
import { Box, Typography } from '@mui/material'
|
||||
import { Box, Typography } from '@mui/material';
|
||||
|
||||
import { REDIRECT_EMAIL_MSG } from '../constants'
|
||||
import { REDIRECT_EMAIL_MSG } from '../constants';
|
||||
|
||||
const Email = () => {
|
||||
return (
|
||||
@ -27,7 +27,7 @@ const Email = () => {
|
||||
{REDIRECT_EMAIL_MSG}
|
||||
</Typography>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export default Email
|
||||
export default Email;
|
||||
|
@ -8,7 +8,7 @@ import SumsubWebSdk from "@sumsub/websdk-react";
|
||||
import { MessageHandler } from "@sumsub/websdk";
|
||||
|
||||
import { config, fetchAccessToken, getAccessTokenExpirationHandler, options } from "../utils/sumsub";
|
||||
import { ENABLE_KYC } from "../constants";
|
||||
import { ENABLE_KYC, SUBSCRIBER_ID_HASH_KEY } from "../constants";
|
||||
|
||||
interface Participant {
|
||||
cosmosAddress: string;
|
||||
@ -25,7 +25,7 @@ const OnboardingSuccess = () => {
|
||||
const location = useLocation();
|
||||
const { cosmosAddress } = location.state as {
|
||||
cosmosAddress?: string
|
||||
}
|
||||
};
|
||||
|
||||
const [participant, setParticipant] = useState<Participant>();
|
||||
const [token, setToken] = useState<string>('');
|
||||
@ -48,6 +48,8 @@ const OnboardingSuccess = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
localStorage.removeItem(SUBSCRIBER_ID_HASH_KEY);
|
||||
|
||||
setParticipant(participant);
|
||||
} catch (error) {
|
||||
console.error("Error fetching participants", error);
|
||||
|
@ -12,6 +12,7 @@ import { StargateClient } from "@cosmjs/stargate";
|
||||
|
||||
import { useWalletConnectContext } from "../context/WalletConnectContext";
|
||||
import SelectRoleCard, {Role} from "../components/SelectRoleCard";
|
||||
import { SUBSCRIBER_ID_HASH_KEY } from "../constants";
|
||||
|
||||
const SignWithCosmos = () => {
|
||||
const { session, signClient } = useWalletConnectContext();
|
||||
@ -25,17 +26,17 @@ const SignWithCosmos = () => {
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
const {message: innerMessage, cosmosAddress, receivedEthSig: ethSignature, subscriberIdHash} = location.state as {
|
||||
const {message: innerMessage, cosmosAddress, receivedEthSig: ethSignature} = location.state as {
|
||||
message?: {
|
||||
msg: string;
|
||||
address: string;
|
||||
};
|
||||
cosmosAddress?: string;
|
||||
receivedEthSig?: string;
|
||||
subscriberIdHash?: string;
|
||||
};
|
||||
|
||||
const ethAddress = innerMessage!.address;
|
||||
const subscriberIdHash = localStorage.getItem(SUBSCRIBER_ID_HASH_KEY);
|
||||
|
||||
const createCosmosClient = useCallback(async (endpoint: string) => {
|
||||
return await StargateClient.connect(endpoint);
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React, { useState, useMemo, useEffect } from "react";
|
||||
import { useLocation, useNavigate } from "react-router-dom";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { enqueueSnackbar } from "notistack";
|
||||
import canonicalStringify from "canonical-json";
|
||||
|
||||
@ -13,7 +13,7 @@ import LoadingButton from '@mui/lab/LoadingButton';
|
||||
import { utf8ToHex } from "@walletconnect/encoding";
|
||||
|
||||
import { useWalletConnectContext } from "../context/WalletConnectContext";
|
||||
import { ENABLE_KYC } from "../constants";
|
||||
import { ENABLE_KYC, SUBSCRIBER_ID_HASH_KEY } from "../constants";
|
||||
|
||||
const SignWithNitroKey = () => {
|
||||
|
||||
@ -27,13 +27,20 @@ const SignWithNitroKey = () => {
|
||||
}, [session, signClient, checkPersistedState]);
|
||||
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
const [ethAddress, setEthAddress] = useState("");
|
||||
const [ethSignature, setEthSignature] = useState("");
|
||||
|
||||
const [cosmosAddress, setCosmosAddress] = useState("");
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const subscriberIdHash = localStorage.getItem(SUBSCRIBER_ID_HASH_KEY);
|
||||
|
||||
useEffect(() => {
|
||||
if (!subscriberIdHash) {
|
||||
setIsLoading(false);
|
||||
enqueueSnackbar("Subscriber ID not found. Please verify your email and try again", { variant: "error" });
|
||||
}
|
||||
}, [subscriberIdHash]);
|
||||
|
||||
const message = useMemo(() => {
|
||||
return {
|
||||
@ -45,7 +52,7 @@ const SignWithNitroKey = () => {
|
||||
const signEth = async () => {
|
||||
if (session && signClient) {
|
||||
try {
|
||||
setIsLoading(true)
|
||||
setIsLoading(true);
|
||||
const jsonMessage = canonicalStringify(message);
|
||||
const hexMsg = utf8ToHex(jsonMessage, true);
|
||||
const receivedEthSig: string = await signClient!.request({
|
||||
@ -56,7 +63,7 @@ const SignWithNitroKey = () => {
|
||||
params: [hexMsg, ethAddress],
|
||||
},
|
||||
});
|
||||
setIsLoading(false)
|
||||
setIsLoading(false);
|
||||
setEthSignature(ethSignature);
|
||||
|
||||
if (ENABLE_KYC) {
|
||||
@ -68,26 +75,17 @@ const SignWithNitroKey = () => {
|
||||
},
|
||||
});
|
||||
} else {
|
||||
const state = location.state as {
|
||||
subscriberIdHash?: string
|
||||
}
|
||||
|
||||
if (!state.subscriberIdHash) {
|
||||
throw new Error("Subscriber ID not found. Please verify your email and try again")
|
||||
}
|
||||
|
||||
navigate("/sign-with-cosmos", {
|
||||
state: {
|
||||
message,
|
||||
cosmosAddress,
|
||||
receivedEthSig,
|
||||
subscriberIdHash: state.subscriberIdHash,
|
||||
},
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("err in signing ", error);
|
||||
setIsLoading(false)
|
||||
setIsLoading(false);
|
||||
enqueueSnackbar("Error signing message", { variant: "error" });
|
||||
}
|
||||
}
|
||||
@ -151,7 +149,7 @@ const SignWithNitroKey = () => {
|
||||
<LoadingButton
|
||||
variant="contained"
|
||||
onClick={signEth}
|
||||
disabled={!Boolean(ethAddress)}
|
||||
disabled={!Boolean(ethAddress) || !subscriberIdHash}
|
||||
sx={{ marginTop: 2 }}
|
||||
loading={isLoading}
|
||||
>
|
||||
|
@ -5,6 +5,8 @@ import { ethers } from 'ethers';
|
||||
|
||||
import { Box, colors, Typography } from '@mui/material';
|
||||
|
||||
import { SUBSCRIBER_ID_HASH_KEY } from '../constants';
|
||||
|
||||
interface JwtPayload {
|
||||
subscriber_id: string;
|
||||
exp: number;
|
||||
@ -24,28 +26,26 @@ const Thanks: React.FC = () => {
|
||||
|
||||
try {
|
||||
if(!token){
|
||||
throw new Error("Invalid JWT Token")
|
||||
throw new Error("Invalid JWT Token");
|
||||
}
|
||||
|
||||
const decoded = jwtDecode(token) as JwtPayload;
|
||||
const currentTime = Math.floor(Date.now() / 1000);
|
||||
|
||||
if (!decoded.subscriber_id) {
|
||||
throw new Error("Subscriber ID not found")
|
||||
throw new Error("Subscriber ID not found");
|
||||
}
|
||||
|
||||
if (decoded.exp < currentTime) {
|
||||
throw new Error("Token has expired");
|
||||
}
|
||||
|
||||
const subscriberIdBytes = ethers.utils.toUtf8Bytes(decoded.subscriber_id)
|
||||
const subscriberIdBytes = ethers.utils.toUtf8Bytes(decoded.subscriber_id);
|
||||
const subscriberIdHash = ethers.utils.sha256(subscriberIdBytes);
|
||||
|
||||
navigate('/connect-wallet', {
|
||||
state:{
|
||||
subscriberIdHash
|
||||
}
|
||||
});
|
||||
localStorage.setItem(SUBSCRIBER_ID_HASH_KEY, subscriberIdHash);
|
||||
|
||||
navigate('/connect-wallet');
|
||||
} catch (error) {
|
||||
setErr(String(error));
|
||||
}
|
||||
|
@ -45,13 +45,14 @@ const UserVerification = () => {
|
||||
useEffect(() => {
|
||||
if (applicationSubmitted && kycId !== '') {
|
||||
const kycIdHash = ethers.utils.sha256(ethers.utils.toUtf8Bytes(kycId));
|
||||
|
||||
navigate("/sign-with-cosmos", {
|
||||
state: {
|
||||
message,
|
||||
cosmosAddress,
|
||||
receivedEthSig,
|
||||
subscriberIdHash: kycIdHash,
|
||||
}})
|
||||
kycIdHash
|
||||
}});
|
||||
}
|
||||
}, [applicationSubmitted, kycId, navigate, cosmosAddress, message, receivedEthSig]);
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React from 'react'
|
||||
import React from 'react';
|
||||
|
||||
const VerifyEmail = () => {
|
||||
return (
|
||||
@ -18,7 +18,7 @@ const VerifyEmail = () => {
|
||||
}}
|
||||
></iframe>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export default VerifyEmail
|
||||
export default VerifyEmail;
|
||||
|
@ -29,5 +29,5 @@ export const getAccessTokenExpirationHandler = (userId: string) => {
|
||||
return async () => {
|
||||
const newToken = await fetchAccessToken(userId);
|
||||
return newToken;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user