Skip to content

Commit

Permalink
Import identity (#42)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>
Co-authored-by: ardier16 <[email protected]>
  • Loading branch information
3 people authored Feb 13, 2024
1 parent aec7573 commit 35ffe13
Show file tree
Hide file tree
Showing 10 changed files with 141 additions and 83 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
4 changes: 1 addition & 3 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ const App: FC<HTMLAttributes<HTMLDivElement>> = () => {
useViewportSizes()

const init = useCallback(async () => {
if (provider?.address) return

try {
const { isMetamaskInstalled, isSnapInstalled } = await web3Store.checkSnapStatus()

Expand All @@ -31,7 +29,7 @@ const App: FC<HTMLAttributes<HTMLDivElement>> = () => {
}

setIsAppInitialized(true)
}, [provider?.address, connectProviders])
}, [connectProviders])

const theme = useMemo(() => createTheme(paletteMode), [paletteMode])

Expand Down
3 changes: 2 additions & 1 deletion src/api/clients/index.ts
Original file line number Diff line number Diff line change
@@ -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,
})
Expand Down
2 changes: 1 addition & 1 deletion src/common/ProfileMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { config } from '@config'
import {
Divider,
ListItemIcon,
Expand All @@ -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'
Expand Down
3 changes: 2 additions & 1 deletion src/helpers/metamask.ts
Original file line number Diff line number Diff line change
@@ -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/'

Expand Down
34 changes: 11 additions & 23 deletions src/hooks/auth.ts
Original file line number Diff line number Diff line change
@@ -1,49 +1,37 @@
import { PROVIDERS } from '@distributedlab/w3p'
import { useCallback, useMemo } from 'react'

import { initZkpSnap, zkpSnap } from '@/api/clients'
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 ({
Expand Down
134 changes: 91 additions & 43 deletions src/pages/SignIn.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<Button
component={'a'}
href={metamaskLink()}
target='_blank'
rel='noreferrer noopener'
startIcon={<UiIcon name={Icons.Metamask} size={5} />}
>
{t('sign-in-page.install-btn')}
</Button>
)
}

return
if (!isSnapInstalled) {
return (
<Button startIcon={<UiIcon name={Icons.Rarime} size={5} />} onClick={installSnap}>
Enable Rarime
</Button>
)
}

setIsPending(true)
if (isImporting) {
return (
<Stack
component={'form'}
spacing={4}
width={spacing(80)}
textAlign={'left'}
onSubmit={e => {
e.preventDefault()
createIdentity(privateKey)
}}
>
<UiTextField
value={privateKey}
type='password'
label='Enter your private key'
disabled={isPending}
helperText='Your private key will be stored in MetaMask'
onChange={e => setPrivateKey(e.target.value)}
/>
<Button type='submit' disabled={!privateKey || isPending}>
{isPending ? 'Importing...' : 'Import'}
</Button>
</Stack>
)
}

window.open(installMMLink, '_blank', 'noopener noreferrer')
}, [installMMLink])
return (
<Stack spacing={4} width={spacing(60)}>
<Button disabled={isPending} onClick={() => createIdentity()}>
{!isPending ? 'Create new Identity' : 'Creating identity...'}
</Button>
<Button color='secondary' disabled={isPending} onClick={() => setIsImporting(true)}>
Import Identity
</Button>
</Stack>
)
}, [
isImporting,
isMetamaskInstalled,
isSnapInstalled,
isPending,
privateKey,
t,
installSnap,
spacing,
createIdentity,
])

return (
<Stack
Expand All @@ -68,26 +131,11 @@ export default function SignIn() {
height: spacing(16),
}}
/>

{/* TODO: add metamask not found texts */}
<Typography variant='h3'>{t('sign-in-page.title')}</Typography>
<Typography variant='body2' color={palette.text.secondary}>
{t('sign-in-page.description')}
</Typography>
<Box>
<UiButton
startIcon={<UiIcon name={Icons.Metamask} size={5} />}
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')}
</UiButton>
</Box>
<Box mt={4}>{renderContent()}</Box>
</Stack>
)
}
12 changes: 10 additions & 2 deletions src/store/modules/identity.module.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type { CreateIdentityRequestParams } from '@rarimo/rarime-connector'

import { zkpSnap } from '@/api/clients'
import { createStore } from '@/helpers'

Expand All @@ -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
Expand Down
14 changes: 14 additions & 0 deletions src/theme/components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,20 @@ export const components: Components<Omit<Theme, '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: {
Expand Down
16 changes: 8 additions & 8 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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"
Expand Down

0 comments on commit 35ffe13

Please sign in to comment.