Skip to content

Commit

Permalink
fix: permissions are reset if dapp doesnt require any methods (#1705)
Browse files Browse the repository at this point in the history
* show different warning if dapp has supported networks on other profile

* only show relevant permissions

---------

Co-authored-by: Nicole O'Brien <[email protected]>
  • Loading branch information
MarkNerdi and nicole-obrien authored Jan 16, 2024
1 parent 480b542 commit 6d65fb0
Show file tree
Hide file tree
Showing 8 changed files with 152 additions and 72 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,23 +29,27 @@
const namespaces = Object.values(requiredNamespaces ?? {})
const _persistedNamespaces = Object.values(persistedNamespaces)
return Object.values(DappPermission).map((permission) => {
const supportedMethods = METHODS_FOR_PERMISSION[permission] ?? []
const isRequired = namespaces.some((namespace) =>
supportedMethods.some((method) => namespace.methods.includes(method))
)
const isEnabled = _persistedNamespaces.some((namespace) =>
supportedMethods.some((method) => namespace.methods.includes(method))
)
return {
label: localize(`views.dashboard.drawers.dapps.confirmConnection.permissions.${String(permission)}`),
enabled: isEnabled,
required: isRequired,
}
})
return Object.values(DappPermission)
.map((permission) => {
const supportedMethods = METHODS_FOR_PERMISSION[permission] ?? []
const isRequired = namespaces.some((namespace) =>
supportedMethods.some((method) => namespace.methods.includes(method))
)
const isEnabled = _persistedNamespaces.some((namespace) =>
supportedMethods.some((method) => namespace.methods.includes(method))
)
return {
label: localize(
`views.dashboard.drawers.dapps.confirmConnection.permissions.${String(permission)}`
),
enabled: isEnabled,
required: isRequired,
}
})
.filter((permission) => permission.enabled)
}
function getNetworkPreferences(): string[] {
Expand Down Expand Up @@ -89,21 +93,26 @@
</script>

<selection-component class="flex flex-col gap-4">
<div class="flex flex-row justify-between">
<Text textColor="secondary">{localize(`${localeKey}.permissions.step`)}</Text>
{#if editable}
<IconButton icon={IconName.SettingsSliders} size="xs" on:click={onEditPermissionsClick} />
{/if}
</div>
<Table>
{#each permissionPreferences as permission}
<TableRow item={{ key: permission.label }}>
<Text textColor={permission.required || permission.enabled ? 'success' : 'warning'} slot="boundValue">
{localize(`general.${permission.required ? 'required' : permission.enabled ? 'yes' : 'no'}`)}
</Text>
</TableRow>
{/each}
</Table>
{#if permissionPreferences.length}
<div class="flex flex-row justify-between">
<Text textColor="secondary">{localize(`${localeKey}.permissions.step`)}</Text>
{#if editable}
<IconButton icon={IconName.SettingsSliders} size="xs" on:click={onEditPermissionsClick} />
{/if}
</div>
<Table>
{#each permissionPreferences as permission}
<TableRow item={{ key: permission.label }}>
<Text
textColor={permission.required || permission.enabled ? 'success' : 'warning'}
slot="boundValue"
>
{localize(`general.${permission.required ? 'required' : permission.enabled ? 'yes' : 'no'}`)}
</Text>
</TableRow>
{/each}
</Table>
{/if}

<div class="flex flex-row justify-between">
<Text textColor="secondary">{localize(`${localeKey}.networks.step`)}</Text>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,41 +1,57 @@
<script lang="ts">
import { ProposalTypes } from '@walletconnect/types'
import { METHODS_FOR_PERMISSION } from '@auxiliary/wallet-connect/constants'
import { DappPermission } from '@auxiliary/wallet-connect/enums'
import { onMount } from 'svelte'
import Selection from './Selection.svelte'
import { localize } from '@core/i18n'
import { SupportedNamespaces } from '@auxiliary/wallet-connect/types'
import { Text } from '@bloomwalletio/ui'
import { getPermissionForMethod } from '@auxiliary/wallet-connect/utils'
export let checkedMethods: string[]
export let requiredNamespaces: ProposalTypes.RequiredNamespaces
export let optionalNamespaces: ProposalTypes.RequiredNamespaces
export let persistedNamespaces: SupportedNamespaces | undefined = undefined
export let permissionSelections: { label: string; value: string; checked: boolean; required: boolean }[] = []
const localeKey = 'views.dashboard.drawers.dapps.confirmConnection.permissions'
let permissionSelections: { label: string; value: string; checked: boolean; required: boolean }[] = []
function setPermissionSelections(): void {
const permissions: { label: string; value: string; checked: boolean; required: boolean }[] = []
const namespaces = Object.values(requiredNamespaces)
for (const permission of Object.values(DappPermission)) {
const supportedMethods = METHODS_FOR_PERMISSION[permission] ?? []
const checkedMethods: { [method: string]: boolean } = {}
const addedPermission: { [permission: string]: boolean } = {}
const isRequired = namespaces.some((namespace) => {
return supportedMethods.some((method) => namespace.methods.includes(method))
})
const methods = [
...Object.values(requiredNamespaces).flatMap((namespace) =>
namespace.methods.map((method) => ({ method, required: true }))
),
...Object.values(optionalNamespaces).flatMap((namespace) =>
namespace.methods.map((method) => ({ method, required: false }))
),
]
for (const method of methods) {
if (checkedMethods[method.method]) {
continue
}
checkedMethods[method.method] = true
const permission = getPermissionForMethod(method.method)
if (!permission || addedPermission[permission]) {
continue
}
addedPermission[permission] = true
const isChecked = persistedNamespaces
? Object.values(persistedNamespaces).some((namespace) => {
return supportedMethods.some((method) => namespace.methods.includes(method))
})
? Object.values(persistedNamespaces).some((namespace) => namespace.methods.includes(method.method))
: true
permissions.push({
label: localize(`views.dashboard.drawers.dapps.confirmConnection.permissions.${String(permission)}`),
value: permission,
checked: isChecked,
required: isRequired,
required: method.required,
})
}
Expand All @@ -55,8 +71,18 @@
})
</script>

<Selection
bind:selectionOptions={permissionSelections}
title={localize(`${localeKey}.title`)}
error={checkedMethods.length ? undefined : localize(`${localeKey}.empty`)}
/>
{#if permissionSelections.length}
<Selection
bind:selectionOptions={permissionSelections}
title={localize(`${localeKey}.title`)}
error={checkedMethods.length ? undefined : localize(`${localeKey}.empty`)}
/>
{:else}
<selection-component class="h-full flex flex-col gap-4">
<Text textColor="secondary">{localize(`${localeKey}.title`)}</Text>

<div class="w-full flex-grow flex justify-center items-center">
<Text type="body2">{localize(`${localeKey}.noPermissionsRequired`)}</Text>
</div>
</selection-component>
{/if}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
localize(`${localeKey}.accounts.step`),
]
let permissionSelections: { label: string; value: string; checked: boolean; required: boolean }[] = []
let checkedAccounts: IAccountState[] = []
let checkedNetworks: string[] = []
let checkedMethods: string[] = []
Expand All @@ -44,7 +45,7 @@
$: isButtonDisabled =
loading ||
(!persistedNamespaces && currentStep === 0 && checkedMethods.length === 0) ||
(!persistedNamespaces && currentStep === 0 && permissionSelections.length && checkedMethods.length === 0) ||
(currentStep === 1 && checkedNetworks.length === 0) ||
(currentStep === 2 && checkedAccounts.length === 0)
Expand Down Expand Up @@ -122,20 +123,22 @@
body={localize(`${localeKey}.${tipLocale}.tip`)}
dismissable={false}
/>
<div class={currentStep === 0 ? 'visible' : 'hidden'}>
<div class="flex-grow {currentStep === 0 ? 'visible' : 'hidden'}">
<PermissionSelection
bind:checkedMethods
bind:permissionSelections
requiredNamespaces={$sessionProposal.params.requiredNamespaces}
optionalNamespaces={$sessionProposal.params.optionalNamespaces}
/>
</div>
<div class={currentStep === 1 ? 'visible' : 'hidden'}>
<div class="flex-grow {currentStep === 1 ? 'visible' : 'hidden'}">
<NetworkSelection
bind:checkedNetworks
requiredNamespaces={$sessionProposal.params.requiredNamespaces}
optionalNamespaces={$sessionProposal.params.optionalNamespaces}
/>
</div>
<div class={currentStep === 2 ? 'visible' : 'hidden'}>
<div class="flex-grow {currentStep === 2 ? 'visible' : 'hidden'}">
<AccountSelection bind:checkedAccounts chainIds={checkedNetworks} />
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@
$: unsupportedMethods = getUnsupportedMethods($sessionProposal)
$: supportedNetworks = getSupportedNetworks($sessionProposal)
$: unsupportedRequiredNetworks = getUnsupportedRequiredNetworks($sessionProposal)
$: isSupportedOnOtherProfiles = areNetworksSupportedOnOtherProfiles(unsupportedRequiredNetworks)
$: fulfillsRequirements =
unsupportedMethods.length === 0 && unsupportedRequiredNetworks.length === 0 && supportedNetworks.length > 0
unsupportedMethods.length === 0 &&
unsupportedRequiredNetworks.networks.length === 0 &&
supportedNetworks.networks.length > 0
let timeout: ReturnType<typeof setTimeout> | undefined
$: {
Expand All @@ -48,17 +49,29 @@
}
}
function getUnsupportedRequiredNetworks(_sessionProposal: Web3WalletTypes.SessionProposal | undefined): string[] {
if (!_sessionProposal) return []
function getUnsupportedRequiredNetworks(_sessionProposal: Web3WalletTypes.SessionProposal | undefined): {
networks: string[]
isSupportedOnOtherProfiles: boolean
} {
if (!_sessionProposal) return { networks: [], isSupportedOnOtherProfiles: false }
const requiredNamespaces = _sessionProposal?.params.requiredNamespaces
const networksSupportedByProfile = getAllNetworkIds()
const requiredNetworks = Object.values(requiredNamespaces).flatMap((namespace) => namespace.chains)
return requiredNetworks.filter((network) => !networksSupportedByProfile.includes(network))
const networks = requiredNetworks.filter((network) => !networksSupportedByProfile.includes(network))
const allSupportedNetworks: string[] = Object.values(SupportedNetworkId)
const isSupportedOnOtherProfiles = networks.every((network) => allSupportedNetworks.includes(network))
return { networks, isSupportedOnOtherProfiles }
}
function getSupportedNetworks(_sessionProposal: Web3WalletTypes.SessionProposal | undefined): string[] {
if (!_sessionProposal) return []
function getSupportedNetworks(_sessionProposal: Web3WalletTypes.SessionProposal | undefined): {
networks: string[]
hasSupportedOnOtherProfiles: boolean
} {
if (!_sessionProposal) return { networks: [], hasSupportedOnOtherProfiles: false }
const requiredNamespaces = _sessionProposal?.params.requiredNamespaces
const optionalNamespaces = _sessionProposal?.params.optionalNamespaces
Expand All @@ -68,13 +81,14 @@
networksSupportedByDapp.push(...Object.values(requiredNamespaces).flatMap((namespace) => namespace.chains))
networksSupportedByDapp.push(...Object.values(optionalNamespaces).flatMap((namespace) => namespace.chains))
const networks = networksSupportedByDapp.filter((network) => networksSupportedByProfile.includes(network))
return networksSupportedByDapp.filter((network) => networksSupportedByProfile.includes(network))
}
function areNetworksSupportedOnOtherProfiles(_unsupportedRequiredNetworks: string[]): boolean {
const allSupportedNetworks: string[] = Object.values(SupportedNetworkId)
return _unsupportedRequiredNetworks.every((network) => allSupportedNetworks.includes(network))
const hasSupportedOnOtherProfiles = networksSupportedByDapp.some((network) =>
allSupportedNetworks.includes(network)
)
return { networks, hasSupportedOnOtherProfiles }
}
function getUnsupportedMethods(_sessionProposal: Web3WalletTypes.SessionProposal | undefined): string[] {
Expand Down Expand Up @@ -131,20 +145,31 @@
</Table>
</div>
</div>
{#if unsupportedRequiredNetworks.length}
{#if unsupportedRequiredNetworks.networks.length}
<div class="flex flex-col gap-8 px-6">
<Alert
variant={isSupportedOnOtherProfiles ? 'warning' : 'danger'}
variant={unsupportedRequiredNetworks.isSupportedOnOtherProfiles ? 'warning' : 'danger'}
text={localize(
`${localeKey}.${
isSupportedOnOtherProfiles ? 'supportedOnOtherProfile' : 'unsupportedNetworks'
unsupportedRequiredNetworks.isSupportedOnOtherProfiles
? 'supportedOnOtherProfile'
: 'unsupportedNetworks'
}`
)}
/>
</div>
{:else if supportedNetworks.length === 0}
{:else if supportedNetworks.networks.length === 0}
<div class="flex flex-col gap-8 px-6">
<Alert variant="danger" text={localize(`${localeKey}.noSupportedNetworks`)} />
<Alert
variant={supportedNetworks.hasSupportedOnOtherProfiles ? 'warning' : 'danger'}
text={localize(
`${localeKey}.${
supportedNetworks.hasSupportedOnOtherProfiles
? 'supportedOnOtherProfile'
: 'noSupportedNetworks'
}`
)}
/>
</div>
{:else if unsupportedMethods.length}
<div class="flex flex-col gap-8 px-6">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
selections={{ methods: checkedMethods }}
let:persistedNamespaces
let:requiredNamespaces
let:optionalNamespaces
disableContinue={checkedMethods.length === 0}
>
<PermissionSelection bind:checkedMethods {requiredNamespaces} {persistedNamespaces} />
<PermissionSelection bind:checkedMethods {requiredNamespaces} {optionalNamespaces} {persistedNamespaces} />
</EditSelectionDrawer>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { METHODS_FOR_PERMISSION } from '../constants'
import { DappPermission } from '../enums'

export function getPermissionForMethod(method: string): DappPermission | undefined {
for (const permission of Object.values(DappPermission)) {
const supportedMethods = METHODS_FOR_PERMISSION[permission] ?? []

if (supportedMethods.includes(method)) {
return permission
}
}

return undefined
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export * from './approveSession'
export * from './disconnectAllDapps'
export * from './getAllEvmAddresses'
export * from './getPermissionForMethod'
export * from './rejectSession'
export * from './switchToRequiredAccount'
export * from './updateSession'
Expand Down
3 changes: 2 additions & 1 deletion packages/shared/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -510,7 +510,8 @@
"signData": "Request to sign data",
"signTransaction": "Request to sign a transaction",
"sendTransaction": "Request to send a transaction",
"empty": "You have to select at least one permission"
"empty": "You have to select at least one permission",
"noPermissionsRequired": "No permissions required to use this app"
},
"networks": {
"step": "Networks",
Expand Down

0 comments on commit 6d65fb0

Please sign in to comment.