Skip to content

Commit

Permalink
WC: dapp warnings (#5147)
Browse files Browse the repository at this point in the history
* init dapp warnings

* fix info alert title weight

* query clean up

* info alert

* i18n

* rm logs

* types + authRequests

* i18n + verified context for wc connections

* fix text padding

* clean up

* lint
  • Loading branch information
skylarbarrera authored Oct 30, 2023
1 parent 452fdcd commit 5f3aa45
Show file tree
Hide file tree
Showing 12 changed files with 508 additions and 42 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@
"react-native-tooltip": "rainbow-me/react-native-tooltip#e0e88d212b5b7f350e5eabba87f588a32e0f2590",
"react-native-tooltips": "rainbow-me/react-native-tooltips#d278f506782d3f39d68ae830c92b8afe670f0e3b",
"react-native-udp": "2.7.0",
"react-native-url-polyfill": "2.0.0",
"react-native-version-number": "0.3.6",
"react-native-video": "5.2.1",
"react-native-video-cache": "2.0.5",
Expand Down
1 change: 1 addition & 0 deletions shim.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'react-native-get-random-values';
import 'react-native-url-polyfill/auto';
import '@ethersproject/shims';
import AsyncStorage from '@react-native-async-storage/async-storage';
import ReactNative from 'react-native';
Expand Down
6 changes: 3 additions & 3 deletions src/components/info-alert/info-alert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export const InfoAlert: React.FC<InfoAlertProps> = ({
style={{
gap: 12,
borderWidth: 2,
borderColor: useForegroundColor('separatorTertiary'),
borderColor: 'red',
}}
flexDirection="row"
borderRadius={20}
Expand All @@ -29,8 +29,8 @@ export const InfoAlert: React.FC<InfoAlertProps> = ({
<Box width={{ custom: 20 }} height={{ custom: 20 }} alignItems="center">
{rightIcon}
</Box>
<Box style={{ gap: 10 }} flexDirection="column">
<Text color="label" size="15pt" weight="heavy">
<Box style={{ gap: 10, paddingRight: 10 }} flexDirection="column">
<Text color="label" size="15pt" weight="bold">
{title}
</Text>
<Text color="labelTertiary" size="13pt" weight="medium">
Expand Down
16 changes: 16 additions & 0 deletions src/graphql/queries/metadata.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,19 @@ query reverseResolveENSProfile(
}
}
}

query getdApp($shortName: String!, $url: String!, $status: Boolean!) {
dApp(shortName: $shortName, url: $url) {
name
status @include(if: $status)
colors {
primary
fallback
shadow
}
iconURL
url
description
shortName
}
}
6 changes: 6 additions & 0 deletions src/languages/en_US.json
Original file line number Diff line number Diff line change
Expand Up @@ -2298,6 +2298,12 @@
"request_invalid": "The request contained invalid parameters. Please try again or contact Rainbow and/or dapp support teams.",
"request_unsupported_network": "The network specified in this request is not supported by Rainbow.",
"request_unsupported_methods": "The RPC method(s) specified in this request are not supported by Rainbow."
},
"dapp_warnings": {
"info_alert": {
"title": "This app is likely malicious",
"description": "Signing messages or transactions from this app could result in losing your assets"
}
}
},
"warning": {
Expand Down
2 changes: 2 additions & 0 deletions src/redux/walletconnect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import { getFCMToken } from '@/notifications/tokens';
import { logger, RainbowError } from '@/logger';
import { IS_DEV, IS_IOS, IS_TEST } from '@/env';
import { RainbowNetworks } from '@/networks';
import { Verify } from '@walletconnect/types';

// -- Variables --------------------------------------- //
let showRedirectSheetThreshold = 300;
Expand Down Expand Up @@ -161,6 +162,7 @@ export interface WalletconnectApprovalSheetRouteParams {
timeout?: ReturnType<typeof setTimeout> | null;
timedOut?: boolean;
failureExplainSheetVariant?: string;
verifiedData?: Verify.Context['verified'];
}

/**
Expand Down
109 changes: 109 additions & 0 deletions src/resources/metadata/dapp.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import { useQuery } from '@tanstack/react-query';
import { metadataClient } from '@/graphql';
import { DAppStatus } from '@/graphql/__generated__/metadata';
import { QueryFunctionArgs, createQueryKey, queryClient } from '@/react-query';

import {
getDappHost,
getDappHostname,
getHardcodedDappInformation,
isValidUrl,
} from '@/utils/connectedApps';
import { capitalize } from 'lodash';

export interface DappMetadata {
url: string;
appHost: string;
appHostName: string;
appName: string;
appShortName: string;
appLogo?: string;
timestamp?: number;
status?: DAppStatus;
}

// ///////////////////////////////////////////////
// Query Types

type DappMetadataArgs = {
url?: string;
};

// ///////////////////////////////////////////////
// Query Key

const DappMetadataQueryKey = ({ url }: DappMetadataArgs) =>
createQueryKey('dappMetadata', { url }, { persisterVersion: 1 });

type DappMetadataQueryKey = ReturnType<typeof DappMetadataQueryKey>;

// ///////////////////////////////////////////////
// Query Function

export async function fetchDappMetadata({
url,
status,
}: {
url: string;
status: boolean;
}) {
const appHostName = url && isValidUrl(url) ? getDappHostname(url) : '';
const hardcodedAppName =
url && isValidUrl(url)
? getHardcodedDappInformation(appHostName)?.name || ''
: '';

const response = await metadataClient.getdApp({
shortName: hardcodedAppName,
url,
status,
});

const appHost = url && isValidUrl(url) ? getDappHost(url) : '';
const appName = response?.dApp?.name
? capitalize(response?.dApp?.name)
: hardcodedAppName || appHost;
const appShortName = response?.dApp?.shortName
? capitalize(response?.dApp?.shortName)
: appName;
const dappMetadata = {
url,
appHost,
appHostName,
appName,
appShortName,
appLogo: response?.dApp?.iconURL,
status: response.dApp?.status,
};
return dappMetadata;
}

export async function dappMetadataQueryFunction({
queryKey: [{ url }],
}: QueryFunctionArgs<
typeof DappMetadataQueryKey
>): Promise<DappMetadata | null> {
if (!url) return null;
const dappMetadata = await fetchDappMetadata({ url, status: true });
return dappMetadata;
}

export async function prefetchDappMetadata({ url }: { url: string }) {
queryClient.prefetchQuery(
DappMetadataQueryKey({ url }),
async () => fetchDappMetadata({ url, status: false }),
{
staleTime: 60000,
}
);
}

// ///////////////////////////////////////////////
// Query Hook

export function useDappMetadata({ url }: DappMetadataArgs) {
return useQuery(DappMetadataQueryKey({ url }), dappMetadataQueryFunction, {
cacheTime: 1000 * 60 * 60 * 24,
enabled: !!url,
});
}
38 changes: 36 additions & 2 deletions src/screens/WalletConnectApprovalSheet.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ import { ETH_ADDRESS, ETH_SYMBOL } from '@/references';
import { AssetType } from '@/entities';
import { RainbowNetworks, getNetworkObj } from '@/networks';
import { IS_IOS } from '@/env';
import { useDappMetadata } from '@/resources/metadata/dapp';
import { DAppStatus } from '@/graphql/__generated__/metadata';
import { InfoAlert } from '@/components/info-alert/info-alert';

const LoadingSpinner = styled(android ? Spinner : ActivityIndicator).attrs(
({ theme: { colors } }) => ({
Expand Down Expand Up @@ -253,6 +256,18 @@ export default function WalletConnectApprovalSheet() {

const { dappName, dappUrl, dappScheme, imageUrl, peerId } = meta;

const verifiedData = params?.verifiedData;
const { data: metadata } = useDappMetadata({
url: verifiedData?.verifyUrl || dappUrl,
});

const isScam = metadata?.status === DAppStatus.Scam;

// disabling Verified for now
const isVerified = false; //metadata?.status === DAppStatus.Verified;

const accentColor = isScam ? colors.red : colors.appleBlue;

useEffect(() => {
return () => {
clearTimeout(timeout);
Expand Down Expand Up @@ -464,15 +479,34 @@ export default function WalletConnectApprovalSheet() {
</Centered>
<Row marginBottom={30} marginTop={30}>
<Text
color="action (Deprecated)"
color={{ custom: accentColor }}
size="18px / 27px (Deprecated)"
weight="heavy"
>
{isScam && '􁅏 '}
{isVerified && '􀇻 '}
{formattedDappUrl}
</Text>
</Row>
<Divider color={colors.rowDividerLight} inset={[0, 84]} />
</Centered>
{isScam && (
<Box paddingHorizontal={'16px'}>
<InfoAlert
rightIcon={
<Text size="15pt" color={{ custom: accentColor }}>
􀘰
</Text>
}
title={lang.t(
lang.l.walletconnect.dapp_warnings.info_alert.title
)}
description={lang.t(
lang.l.walletconnect.dapp_warnings.info_alert.description
)}
/>
</Box>
)}
<SheetActionButtonRow paddingBottom={android ? 20 : 30}>
<SheetActionButton
color={colors.white}
Expand All @@ -483,7 +517,7 @@ export default function WalletConnectApprovalSheet() {
weight="bold"
/>
<SheetActionButton
color={colors.appleBlue}
color={accentColor}
label={lang.t('button.connect')}
onPress={handleConnect}
size="big"
Expand Down
Loading

0 comments on commit 5f3aa45

Please sign in to comment.