From 35ffe13097a0a088f2cc960583909ae910491fe4 Mon Sep 17 00:00:00 2001 From: Nikita Belous <88971585+WhiteNik16@users.noreply.github.com> Date: Tue, 13 Feb 2024 11:30:58 +0200 Subject: [PATCH] Import identity (#42) * refactore sign in page * update after review * fix identity creation * hotfix * Pass private key to import identity * hotfix sign-in install snap flow * Fix review issues * Move SignIn back --------- Co-authored-by: lukachi Co-authored-by: ardier16 --- package.json | 2 +- src/App.tsx | 4 +- src/api/clients/index.ts | 3 +- src/common/ProfileMenu.tsx | 2 +- src/helpers/metamask.ts | 3 +- src/hooks/auth.ts | 34 +++---- src/pages/SignIn.tsx | 134 ++++++++++++++++++--------- src/store/modules/identity.module.ts | 12 ++- src/theme/components.ts | 14 +++ yarn.lock | 16 ++-- 10 files changed, 141 insertions(+), 83 deletions(-) diff --git a/package.json b/package.json index 69a15c06..c54a8a60 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "@mui/icons-material": "^5.14.19", "@mui/material": "^5.14.20", "@mui/x-date-pickers": "^6.18.7", - "@rarimo/rarime-connector": "^2.1.0-rc.0", + "@rarimo/rarime-connector": "^2.1.0-rc.2", "@walletconnect/modal": "^2.6.2", "copy-to-clipboard": "^3.3.3", "i18next": "^22.4.3", diff --git a/src/App.tsx b/src/App.tsx index bc727f7c..6be012df 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -18,8 +18,6 @@ const App: FC> = () => { useViewportSizes() const init = useCallback(async () => { - if (provider?.address) return - try { const { isMetamaskInstalled, isSnapInstalled } = await web3Store.checkSnapStatus() @@ -31,7 +29,7 @@ const App: FC> = () => { } setIsAppInitialized(true) - }, [provider?.address, connectProviders]) + }, [connectProviders]) const theme = useMemo(() => createTheme(paletteMode), [paletteMode]) diff --git a/src/api/clients/index.ts b/src/api/clients/index.ts index 7958102a..1cfbd373 100644 --- a/src/api/clients/index.ts +++ b/src/api/clients/index.ts @@ -1,7 +1,8 @@ -import { config } from '@config' import { JsonApiClient } from '@distributedlab/jac' import { enableSnap, SnapConnector } from '@rarimo/rarime-connector' +import { config } from '@/config' + export const api = new JsonApiClient({ baseUrl: config.API_URL, }) diff --git a/src/common/ProfileMenu.tsx b/src/common/ProfileMenu.tsx index 7885a335..67ee827f 100644 --- a/src/common/ProfileMenu.tsx +++ b/src/common/ProfileMenu.tsx @@ -1,4 +1,3 @@ -import { config } from '@config' import { Divider, ListItemIcon, @@ -13,6 +12,7 @@ import { useState } from 'react' import { Link } from 'react-router-dom' import { UserAvatar } from '@/common' +import { config } from '@/config' import { BusEvents } from '@/enums' import { bus, formatDid } from '@/helpers' import { useAuth, useCopyToClipboard } from '@/hooks' diff --git a/src/helpers/metamask.ts b/src/helpers/metamask.ts index 331dfd48..1ae529d0 100644 --- a/src/helpers/metamask.ts +++ b/src/helpers/metamask.ts @@ -1,7 +1,8 @@ import get from 'lodash/get' const OTHER_BROWSER_METAMASK_LINK = 'https://metamask.io/download/' -const CHROME_METAMASK_ADDON_LINK = 'https://chrome.google.com/webstore/detail/metamask/' +const CHROME_METAMASK_ADDON_LINK = + 'https://chromewebstore.google.com/detail/metamask/nkbihfbeogaeaoehlefnkodbefgpgknn' const FIREFOX_METAMASK_ADDON_LINK = 'https://addons.mozilla.org/en-US/firefox/addon/ether-metamask/' const OPERA_METAMASK_ADDON_LINK = 'https://addons.opera.com/en/extensions/details/metamask-10/' diff --git a/src/hooks/auth.ts b/src/hooks/auth.ts index f1db29f7..5e45e33a 100644 --- a/src/hooks/auth.ts +++ b/src/hooks/auth.ts @@ -1,4 +1,3 @@ -import { PROVIDERS } from '@distributedlab/w3p' import { useCallback, useMemo } from 'react' import { initZkpSnap, zkpSnap } from '@/api/clients' @@ -6,44 +5,33 @@ import { authorizeUser } from '@/api/modules/auth' import { OrgUserRoles } from '@/api/modules/orgs' import { buildAuthorizeRequest, getClaimOffer } from '@/api/modules/zkp' import { useWeb3Context } from '@/hooks/web3' -import { identityStore, useIdentityState, web3Store } from '@/store' +import { identityStore, useIdentityState, useWeb3State, web3Store } from '@/store' // TODO: add jwt validations for specific org export const useAuth = () => { - const { init, provider } = useWeb3Context() + const { provider } = useWeb3Context() const { userDid } = useIdentityState() + const { isSnapInstalled } = useWeb3State() const isAuthorized = useMemo( - () => Boolean(provider?.isConnected && userDid), - [provider?.isConnected, userDid], + () => Boolean(userDid && isSnapInstalled), + [isSnapInstalled, userDid], ) const logout = useCallback(async () => { - await provider?.disconnect() await web3Store.checkSnapStatus() web3Store.setProviderType(undefined) - }, [provider]) + }, []) - const connectProviders = useCallback( - async (providerType?: PROVIDERS) => { - const currentProviderType = providerType || web3Store.providerType + const connectProviders = useCallback(async () => { + await initZkpSnap() - web3Store.setProviderType(currentProviderType) - - if (!currentProviderType) return - - await init(currentProviderType) - - await initZkpSnap() - - await web3Store.checkSnapStatus() + await web3Store.checkSnapStatus() - return identityStore.createIdentity() - }, - [init], - ) + return identityStore.getIdentity() + }, []) const authorize = useCallback( async ({ diff --git a/src/pages/SignIn.tsx b/src/pages/SignIn.tsx index 221d644a..1912af5b 100644 --- a/src/pages/SignIn.tsx +++ b/src/pages/SignIn.tsx @@ -1,51 +1,114 @@ -import { PROVIDERS } from '@distributedlab/w3p' -import { Box, Stack, Typography, useTheme } from '@mui/material' -import { useCallback, useMemo, useState } from 'react' +import { Box, Button, Stack, Typography, useTheme } from '@mui/material' +import { useCallback, useState } from 'react' import { useTranslation } from 'react-i18next' import { config } from '@/config' -import { BusEvents, Icons } from '@/enums' -import { bus, ErrorHandler, metamaskLink } from '@/helpers' +import { Icons } from '@/enums' +import { ErrorHandler, metamaskLink } from '@/helpers' import { useAuth } from '@/hooks' -import { useWeb3State } from '@/store' -import { UiButton, UiIcon } from '@/ui' +import { identityStore, useWeb3State } from '@/store' +import { UiIcon, UiTextField } from '@/ui' export default function SignIn() { const { t } = useTranslation() - const { connectProviders } = useAuth() - const [isPending, setIsPending] = useState(false) - const { palette, spacing } = useTheme() - const { isMetamaskInstalled } = useWeb3State() - const signIn = useCallback(async () => { - setIsPending(true) + const { connectProviders } = useAuth() + const { isSnapInstalled, isMetamaskInstalled } = useWeb3State() + const [isPending, setIsPending] = useState(false) + const [isImporting, setIsImporting] = useState(false) + const [privateKey, setPrivateKey] = useState('') + + const installSnap = useCallback(async () => { try { - await connectProviders(PROVIDERS.Metamask) + await connectProviders() } catch (error) { ErrorHandler.process(error) - setIsPending(false) } }, [connectProviders]) - const installMMLink = useMemo(() => { - if (isMetamaskInstalled) return '' - - return metamaskLink() - }, [isMetamaskInstalled]) + const createIdentity = useCallback(async (privateKeyHex?: string) => { + setIsPending(true) + try { + await identityStore.createIdentity({ privateKeyHex }) + } catch (error) { + ErrorHandler.process(error) + } + setIsPending(false) + }, []) - const openInstallMetamaskLink = useCallback(() => { - if (!installMMLink) { - bus.emit(BusEvents.warning, `Your browser is not support Metamask`) + const renderContent = useCallback(() => { + if (!isMetamaskInstalled) { + return ( + + ) + } - return + if (!isSnapInstalled) { + return ( + + ) } - setIsPending(true) + if (isImporting) { + return ( + { + e.preventDefault() + createIdentity(privateKey) + }} + > + setPrivateKey(e.target.value)} + /> + + + ) + } - window.open(installMMLink, '_blank', 'noopener noreferrer') - }, [installMMLink]) + return ( + + + + + ) + }, [ + isImporting, + isMetamaskInstalled, + isSnapInstalled, + isPending, + privateKey, + t, + installSnap, + spacing, + createIdentity, + ]) return ( - - {/* TODO: add metamask not found texts */} {t('sign-in-page.title')} {t('sign-in-page.description')} - - } - disabled={isPending} - sx={{ mt: 8 }} - onClick={isMetamaskInstalled ? signIn : openInstallMetamaskLink} - > - {isMetamaskInstalled - ? t('sign-in-page.connect-btn') - : isPending - ? t('sign-in-page.reload-page-btn') - : t('sign-in-page.install-btn')} - - + {renderContent()} ) } diff --git a/src/store/modules/identity.module.ts b/src/store/modules/identity.module.ts index 3cfbba2c..39c7c401 100644 --- a/src/store/modules/identity.module.ts +++ b/src/store/modules/identity.module.ts @@ -1,3 +1,5 @@ +import type { CreateIdentityRequestParams } from '@rarimo/rarime-connector' + import { zkpSnap } from '@/api/clients' import { createStore } from '@/helpers' @@ -13,8 +15,14 @@ const [identityStore, useIdentityState] = createStore( userDidBigIntString: '', } as IdentityState, state => ({ - createIdentity: async () => { - const { identityIdString, identityIdBigIntString } = await zkpSnap.createIdentity({}) + createIdentity: async (params: CreateIdentityRequestParams) => { + const { identityIdString, identityIdBigIntString } = await zkpSnap.createIdentity(params) + + state.userDid = identityIdString + state.userDidBigIntString = identityIdBigIntString + }, + getIdentity: async () => { + const { identityIdString, identityIdBigIntString } = await zkpSnap.getIdentity() state.userDid = identityIdString state.userDidBigIntString = identityIdBigIntString diff --git a/src/theme/components.ts b/src/theme/components.ts index b52ce190..5b447387 100644 --- a/src/theme/components.ts +++ b/src/theme/components.ts @@ -98,6 +98,20 @@ export const components: Components> = { color: theme.palette.secondary.main, }, }), + containedPrimary: ({ theme }) => ({ + '&:disabled': { + backgroundColor: theme.palette.primary.main, + color: theme.palette.text.primary, + opacity: 0.5, + }, + }), + containedSecondary: ({ theme }) => ({ + color: theme.palette.text.primary, + backgroundColor: theme.palette.action.active, + '&:hover': { + backgroundColor: theme.palette.action.hover, + }, + }), }, }, MuiButtonBase: { diff --git a/yarn.lock b/yarn.lock index 20c05b63..b21841d0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1124,12 +1124,12 @@ __metadata: linkType: hard "@floating-ui/dom@npm:^1.6.1": - version: 1.6.2 - resolution: "@floating-ui/dom@npm:1.6.2" + version: 1.6.3 + resolution: "@floating-ui/dom@npm:1.6.3" dependencies: "@floating-ui/core": "npm:^1.0.0" "@floating-ui/utils": "npm:^0.2.0" - checksum: 3c97daeb231d88f443ad92800a8d0256c91da16bce4d3e04d9daa4ba6e9484e16ccc91782913ab8d38067de3f789b051e3a78690acca7baf4aeb276afc418808 + checksum: d6cac10877918ce5a8d1a24b21738d2eb130a0191043d7c0dd43bccac507844d3b4dc5d4107d3891d82f6007945ca8fb4207a1252506e91c37e211f0f73cf77e languageName: node linkType: hard @@ -1841,14 +1841,14 @@ __metadata: languageName: node linkType: hard -"@rarimo/rarime-connector@npm:^2.1.0-rc.0": - version: 2.1.0-rc.0 - resolution: "@rarimo/rarime-connector@npm:2.1.0-rc.0" +"@rarimo/rarime-connector@npm:^2.1.0-rc.2": + version: 2.1.0-rc.2 + resolution: "@rarimo/rarime-connector@npm:2.1.0-rc.2" dependencies: "@ethersproject/providers": "npm:5.7.2" compare-versions: "npm:^6.1.0" ethers: "npm:5.7.2" - checksum: a708f0fbd618a0f9a5184276d77a013dc4ac2d289bf2fc0caeb98bcb99c5282a8cb1e00c4a47cc01f3e29aacdd0146a8b869d5dc37fbfd66972f6d09d76f0632 + checksum: 235886185c861b5cfec3f1ef4644becb84a1dd7b9cbbf029de6e1bd789cd2ae65e0e6aaccce22c3449317eedaf361368efa4cd0dd82a29f784f64f8215b81c3b languageName: node linkType: hard @@ -8922,7 +8922,7 @@ __metadata: "@mui/icons-material": "npm:^5.14.19" "@mui/material": "npm:^5.14.20" "@mui/x-date-pickers": "npm:^6.18.7" - "@rarimo/rarime-connector": "npm:^2.1.0-rc.0" + "@rarimo/rarime-connector": "npm:^2.1.0-rc.2" "@types/lodash": "npm:^4" "@types/react": "npm:^18.2.37" "@types/react-dom": "npm:^18.2.15"