Skip to content

Commit

Permalink
feat(passport): account mask address
Browse files Browse the repository at this point in the history
  • Loading branch information
szkl committed Nov 30, 2023
1 parent 6c9c706 commit b4e2566
Show file tree
Hide file tree
Showing 42 changed files with 1,053 additions and 468 deletions.
Binary file not shown.
Binary file not shown.
18 changes: 11 additions & 7 deletions apps/passport/app/components/accounts/AccountList.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { AccountURNSpace } from '@proofzero/urns/account'
import type { AccountURN } from '@proofzero/urns/account'

import { EmailAccountType } from '@proofzero/types/account'

import { List } from '@proofzero/design-system/src/atoms/lists/List'
import { Text } from '@proofzero/design-system/src/atoms/text/Text'

Expand All @@ -22,13 +24,15 @@ export const AccountList = ({
}: AccountListProps) => {
return accounts.length ? (
<List
items={accounts.map((ali) => ({
key: ali.id,
val: ali,
primary:
AccountURNSpace.decode(ali.id as AccountURN) ===
AccountURNSpace.decode(primaryAccountURN),
}))}
items={accounts
.filter((ali) => ali.type !== EmailAccountType.Mask)
.map((ali) => ({
key: ali.id,
val: ali,
primary:
AccountURNSpace.decode(ali.id as AccountURN) ===
AccountURNSpace.decode(primaryAccountURN),
}))}
itemRenderer={(item) => (
<AccountListItem
key={item.key}
Expand Down
62 changes: 43 additions & 19 deletions apps/passport/app/components/applications/claims.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import { Form, useTransition } from '@remix-run/react'

import { Button, Text } from '@proofzero/design-system'
import { FaChevronDown, FaChevronRight } from 'react-icons/fa'
import { TbShield } from 'react-icons/tb'

import { EmailAccountType } from '@proofzero/types/account'

import MultiAvatar from '@proofzero/design-system/src/molecules/avatar/MultiAvatar'
import UserPill from '@proofzero/design-system/src/atoms/pills/UserPill'
Expand All @@ -10,12 +13,14 @@ import { Disclosure } from '@headlessui/react'
import { useState } from 'react'

import passportLogoURL from '~/assets/PassportIcon.svg'
import { HiOutlineMail } from 'react-icons/hi'
import { TbCrown } from 'react-icons/tb'
import { Modal } from '@proofzero/design-system/src/molecules/modal/Modal'
import warningImg from '~/assets/warning.svg'
import InputText from '~/components/inputs/InputText'
import { startCase } from 'lodash'
import { HiOutlineExternalLink, HiOutlineX } from 'react-icons/hi'
import { EmailMaskedPill } from '@proofzero/design-system/src/atoms/pills/EmailMaskPill'

export const ConfirmRevocationModal = ({
title,
Expand Down Expand Up @@ -129,11 +134,16 @@ const AccountExpandedView = ({
<div className="flex flex-col gap-2 p-2.5 bg-white rounded-lg">
{connectedAccounts && (
<section className="flex flex-row gap-2 items-center">
<img src={account.icon} className="rounded-full w-5 h-5" />
{account.type === EmailAccountType.Mask ? (
<TbShield />
) : (
<img src={account.icon} className="rounded-full w-5 h-5" />
)}

<Text size="sm" weight="semibold" className="text-gray-800 truncate">
{account.address}
</Text>
{account.type === EmailAccountType.Mask ? <EmailMaskedPill /> : null}
</section>
)}

Expand Down Expand Up @@ -171,12 +181,14 @@ export const ClaimsMobileView = ({ scopes }: { scopes: any[] }) => {
const RowView = ({
account,
appAskedFor,
masked = false,
whatsBeingShared,
sourceOfData,
sourceOfDataIcon,
dropdown = true,
}: {
appAskedFor: string
masked: boolean
sourceOfData: string
sourceOfDataIcon: JSX.Element
dropdown?: boolean
Expand All @@ -203,6 +215,7 @@ export const ClaimsMobileView = ({ scopes }: { scopes: any[] }) => {
>
{appAskedFor}
</Text>
{masked && <EmailMaskedPill />}
{whatsBeingShared && (
<Text
size="sm"
Expand All @@ -229,6 +242,7 @@ export const ClaimsMobileView = ({ scopes }: { scopes: any[] }) => {
>
{appAskedFor}
</Text>
{masked && <EmailMaskedPill />}
{whatsBeingShared && (
<Text
size="sm"
Expand Down Expand Up @@ -373,6 +387,7 @@ export const ClaimsMobileView = ({ scopes }: { scopes: any[] }) => {
size={20}
text={scWallets ? a.title! : a.address}
avatarURL={a.icon}
masked={a.type === EmailAccountType.Mask}
onClick={() => setSelectedAccount(a)}
className={'pointer-events-auto'}
/>
Expand Down Expand Up @@ -421,11 +436,10 @@ export const ClaimsMobileView = ({ scopes }: { scopes: any[] }) => {
<RowView
key={i}
appAskedFor="Email"
whatsBeingShared={scope.account}
masked={scope.masked}
whatsBeingShared={scope.address}
sourceOfData={scope.account}
sourceOfDataIcon={
<img src={scope.icon} className="w-5 h-5 rounded-full" />
}
sourceOfDataIcon={<HiOutlineMail className="w-5 h-5" />}
dropdown={false}
/>
)
Expand Down Expand Up @@ -491,12 +505,14 @@ export const ClaimsWideView = ({ scopes }: { scopes: any[] }) => {
const RowView = ({
account,
appAskedFor,
masked = false,
whatsBeingShared,
sourceOfData,
sourceOfDataIcon,
dropdown = true,
}: {
appAskedFor: string
masked: boolean
sourceOfData: string
sourceOfDataIcon: JSX.Element
dropdown?: boolean
Expand Down Expand Up @@ -527,15 +543,19 @@ export const ClaimsWideView = ({ scopes }: { scopes: any[] }) => {
>
{appAskedFor}
</Text>
{masked && <EmailMaskedPill />}
</Disclosure.Button>
) : (
<Text
size="sm"
weight="medium"
className="text-gray-500 truncate"
>
{appAskedFor}
</Text>
<div className="flex space-x-1">
<Text
size="sm"
weight="medium"
className="text-gray-500 truncate"
>
{appAskedFor}
</Text>
{masked && <EmailMaskedPill />}
</div>
)}
</td>
<td className="px-6 py-3">
Expand Down Expand Up @@ -636,6 +656,7 @@ export const ClaimsWideView = ({ scopes }: { scopes: any[] }) => {
| {
icon: string
address: string
source: string
type: string
title?: string
}
Expand Down Expand Up @@ -675,7 +696,9 @@ export const ClaimsWideView = ({ scopes }: { scopes: any[] }) => {
Wallet(s)
</Text>
) : (
<MultiAvatar avatars={accounts.map((a) => a.icon)!} />
<MultiAvatar
avatars={accounts.filter((a) => a.icon).map((a) => a.icon)}
/>
)}
</td>
<td className="px-6 py-3 flex flex-row items-center gap-2.5">
Expand Down Expand Up @@ -706,6 +729,7 @@ export const ClaimsWideView = ({ scopes }: { scopes: any[] }) => {
size={20}
text={scWallets ? a.title! : a.address}
avatarURL={a.icon}
masked={a.type === EmailAccountType.Mask}
onClick={() => setSelectedAccount(a)}
className={'pointer-events-auto'}
/>
Expand All @@ -717,7 +741,8 @@ export const ClaimsWideView = ({ scopes }: { scopes: any[] }) => {
source={
source
? source
: `${startCase(selectedAccount.type)} - ${
: selectedAccount.source ||
`${startCase(selectedAccount.type)} - ${
selectedAccount.address
}`
}
Expand Down Expand Up @@ -754,11 +779,10 @@ export const ClaimsWideView = ({ scopes }: { scopes: any[] }) => {
<RowView
key={i}
appAskedFor="Email"
whatsBeingShared={scope.account}
sourceOfData={scope.account}
sourceOfDataIcon={
<img src={scope.icon} className="w-5 h-5 rounded-full" />
}
masked={scope.masked}
whatsBeingShared={scope.address}
sourceOfData={scope.masked ? scope.source : scope.address}
sourceOfDataIcon={<HiOutlineMail className="w-5 h-5" />}
dropdown={false}
/>
)
Expand Down
74 changes: 67 additions & 7 deletions apps/passport/app/routes/authorize.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -325,9 +325,7 @@ export const action: ActionFunction = async ({ request, context }) => {
const scope = (form.get('scopes') as string).split(' ')
/* This stores the selection made from the user in the authorization
screen; gets validated and stored for later retrieval at token generation stage */
const personaData = JSON.parse(
form.get('personaData') as string
) as PersonaData
let personaData = JSON.parse(form.get('personaData') as string) as PersonaData

const state = form.get('state') as string
const clientId = form.get('client_id') as string
Expand Down Expand Up @@ -397,13 +395,13 @@ export const action: ActionFunction = async ({ request, context }) => {
}

export default function Authorize() {
const loaderData = useLoaderData<LoaderData>()
const {
clientId,
appProfile,
scopeMeta,
state,
redirectOverride,
dataForScopes,
redirectUri,
profile,
prompt,
Expand All @@ -412,10 +410,11 @@ export default function Authorize() {

const userProfile = profile as UserProfile

const [dataForScopes, setDataForScopes] = useState(loaderData.dataForScopes)
const {
connectedEmails,
personaData,
requestedScope,
connectedEmails,
connectedAccounts,
connectedSmartContractWallets,
} = dataForScopes as DataForScopes
Expand All @@ -434,6 +433,54 @@ export default function Authorize() {
}
return selected
})

const [maskEmail, setMaskEmail] = useState<boolean>(false)
useEffect(() => {
setMaskEmailCallback()
})

const [loadingMaskEmail, setLoadingMaskEmail] = useState<boolean>(false)

const setMaskEmailCallback = async () => {
if (!maskEmail) return

const accountURN = selectedEmail?.value
if (!accountURN) return
if (selectedEmail.mask) return

setLoadingMaskEmail(true)

const response = await fetch('/create/account-mask', {
body: JSON.stringify({ accountURN, clientId }),
headers: { 'Content-Type': 'application/json' },
method: 'POST',
})

let maskAccount = selectedEmail
const [mask] = await response.json<DropdownSelectListItem[]>()

setDataForScopes((state) => ({
...state,
connectedAccounts: connectedAccounts.map((ca) => {
if (ca.value !== accountURN) return ca
return {
...ca,
mask,
}
}),
connectedEmails: connectedEmails.map((ce) => {
if (ce.value !== accountURN) return ce
maskAccount = {
...ce,
mask,
}
return maskAccount
}),
}))
setSelectedEmail(maskAccount)
setLoadingMaskEmail(false)
}

const [selectedConnectedAccounts, setSelectedConnectedAccounts] = useState<
Array<DropdownSelectListItem> | Array<AuthorizationControlSelection>
>(() => {
Expand Down Expand Up @@ -510,7 +557,9 @@ export default function Authorize() {
}

if (requestedScope.includes('email') && selectedEmail) {
personaData.email = selectedEmail.value
personaData.email = maskEmail
? selectedEmail.mask?.value
: selectedEmail.value
}

if (
Expand All @@ -521,7 +570,12 @@ export default function Authorize() {
personaData.connected_accounts = AuthorizationControlSelection.ALL
} else {
personaData.connected_accounts = selectedConnectedAccounts.map(
(account) => (account as DropdownSelectListItem).value
(account) => {
const item = account as DropdownSelectListItem
if (!maskEmail) return item.value
if (item.value === selectedEmail?.value) return item.mask?.value
return item.value
}
)
}
}
Expand Down Expand Up @@ -640,10 +694,13 @@ export default function Authorize() {
// Substituting subtitle with icon
// on the client side
return {
address: email.address,
type: email.type,
icon: getEmailIcon(email.subtitle!),
title: email.title,
selected: email.selected,
value: email.value,
mask: email.mask,
}
}) ?? []
}
Expand All @@ -661,6 +718,9 @@ export default function Authorize() {
}}
selectEmailCallback={setSelectedEmail}
selectedEmail={selectedEmail}
maskEmail={maskEmail}
loadingMaskEmail={loadingMaskEmail}
setMaskEmail={setMaskEmail}
connectedAccounts={connectedAccounts ?? []}
selectedConnectedAccounts={selectedConnectedAccounts}
addNewAccountCallback={() => {
Expand Down
Loading

0 comments on commit b4e2566

Please sign in to comment.