From a8996a8872ef150e13c993410a65a251f72bc900 Mon Sep 17 00:00:00 2001 From: Tomas Martykan Date: Thu, 6 Feb 2025 16:34:49 +0100 Subject: [PATCH] chore: unify mobile and desktop connect popup logic --- .../UserContextModal/ConnectPopupModal.tsx | 8 +- .../src/connectPopupMiddleware.ts | 2 +- .../connect-popup/src/connectPopupReducer.ts | 5 +- .../connect-popup/src/connectPopupThunks.ts | 105 ++++++++++++-- .../connect-popup/src/connectPopupTypes.ts | 25 +++- .../walletconnect/src/adapters/ethereum.ts | 3 - suite-native/intl/src/en.ts | 1 + .../module-connect-popup/package.json | 2 +- suite-native/module-connect-popup/redux.d.ts | 7 + .../src/hooks/useConnectMethod.ts | 49 ------- .../src/hooks/useConnectParseParams.ts | 47 ------- .../src/hooks/useConnectPopupNavigation.ts | 18 ++- .../src/screens/ConnectPopupScreen.tsx | 131 +++++------------- .../src/utils/callbackURLOrigin.ts | 9 -- .../module-connect-popup/tsconfig.json | 1 - suite-native/navigation/package.json | 1 - suite-native/navigation/src/navigators.ts | 5 +- suite-native/state/src/reducers.ts | 3 + yarn.lock | 8 +- 19 files changed, 190 insertions(+), 240 deletions(-) create mode 100644 suite-native/module-connect-popup/redux.d.ts delete mode 100644 suite-native/module-connect-popup/src/hooks/useConnectMethod.ts delete mode 100644 suite-native/module-connect-popup/src/hooks/useConnectParseParams.ts delete mode 100644 suite-native/module-connect-popup/src/utils/callbackURLOrigin.ts diff --git a/packages/suite/src/components/suite/modals/ReduxModal/UserContextModal/ConnectPopupModal.tsx b/packages/suite/src/components/suite/modals/ReduxModal/UserContextModal/ConnectPopupModal.tsx index a6a550d6095..e93d2a8b0f6 100644 --- a/packages/suite/src/components/suite/modals/ReduxModal/UserContextModal/ConnectPopupModal.tsx +++ b/packages/suite/src/components/suite/modals/ReduxModal/UserContextModal/ConnectPopupModal.tsx @@ -9,9 +9,9 @@ import { useDispatch, useSelector } from 'src/hooks/suite'; export const ConnectPopupModal = () => { const dispatch = useDispatch(); const popupCall = useSelector(selectConnectPopupCall); - if (!popupCall) return null; + if (!popupCall || popupCall?.state !== 'request') return null; - const { method, processName, origin } = popupCall; + const { methodTitle, confirmLabel, processName, origin } = popupCall; const onConfirm = () => dispatch(connectPopupActions.approveCall()); const onCancel = () => dispatch(connectPopupActions.rejectCall(ERRORS.TypedError('Method_Cancel'))); @@ -27,13 +27,13 @@ export const ConnectPopupModal = () => { - + {confirmLabel || } } heading={} > -

{method}

+

{methodTitle}

{processName && ( diff --git a/suite-common/connect-popup/src/connectPopupMiddleware.ts b/suite-common/connect-popup/src/connectPopupMiddleware.ts index 93a1a9ce544..6bced311f20 100644 --- a/suite-common/connect-popup/src/connectPopupMiddleware.ts +++ b/suite-common/connect-popup/src/connectPopupMiddleware.ts @@ -6,7 +6,7 @@ export const prepareConnectPopupMiddleware = createMiddlewareWithExtraDeps( async (action, { dispatch, next, extra }) => { await next(action); - if (connectPopupActions.initiateCall.match(action)) { + if (connectPopupActions.initiateCall.match(action) && action.payload.state === 'request') { dispatch(extra.actions.openModal({ type: 'connect-popup' })); } if ( diff --git a/suite-common/connect-popup/src/connectPopupReducer.ts b/suite-common/connect-popup/src/connectPopupReducer.ts index 3e95ba38087..41265b236f0 100644 --- a/suite-common/connect-popup/src/connectPopupReducer.ts +++ b/suite-common/connect-popup/src/connectPopupReducer.ts @@ -23,11 +23,12 @@ export const prepareConnectPopupReducer = createReducerWithExtraDeps( state.activeCall = payload; }) .addCase(connectPopupActions.approveCall, state => { - state?.activeCall?.confirmation.resolve(); + if (state.activeCall?.state === 'request') state.activeCall.confirmation.resolve(); state.activeCall = undefined; }) .addCase(connectPopupActions.rejectCall, (state, { payload }) => { - state?.activeCall?.confirmation.reject(payload); + if (state.activeCall?.state === 'request') + state.activeCall.confirmation.reject(payload); state.activeCall = undefined; }); }, diff --git a/suite-common/connect-popup/src/connectPopupThunks.ts b/suite-common/connect-popup/src/connectPopupThunks.ts index 19660bf264c..3e94efa879f 100644 --- a/suite-common/connect-popup/src/connectPopupThunks.ts +++ b/suite-common/connect-popup/src/connectPopupThunks.ts @@ -1,9 +1,10 @@ import { AsyncThunkAction } from '@reduxjs/toolkit'; import { CustomThunkAPI, createThunk } from '@suite-common/redux-utils'; -import { selectSelectedDevice } from '@suite-common/wallet-core'; +import { deviceActions, selectSelectedDevice } from '@suite-common/wallet-core'; import TrezorConnect, { CallMethodParams, CallMethodResponse, ERRORS } from '@trezor/connect'; -import { serializeError } from '@trezor/connect/src/constants/errors'; +import { TypedError, serializeError } from '@trezor/connect/src/constants/errors'; +import { DEEPLINK_VERSION } from '@trezor/connect/src/data/version'; import { createDeferred } from '@trezor/utils'; import { connectPopupActions } from './connectPopupActions'; @@ -11,13 +12,11 @@ import { connectPopupActions } from './connectPopupActions'; const CONNECT_POPUP_MODULE = '@common/connect-popup'; type ConnectPopupCallThunkResponse = Promise<{ - id: number; success: boolean; payload: CallMethodResponse; }>; type ConnectPopupCallThunkParams = { - id: number; processName?: string; origin?: string; method: M; @@ -29,7 +28,7 @@ export const connectPopupCallThunkInner = createThunk< ConnectPopupCallThunkParams >( `${CONNECT_POPUP_MODULE}/callThunk`, - async ({ id, method, payload, processName, origin }, { dispatch, getState, extra }) => { + async ({ method, payload, processName, origin }, { dispatch, getState, extra }) => { try { // @ts-expect-error: method is dynamic const methodInfo = await TrezorConnect[method]({ @@ -37,14 +36,32 @@ export const connectPopupCallThunkInner = createThunk< __info: true, }); if (!methodInfo.success) { + connectPopupActions.initiateCall({ + state: 'call-error', + callError: ERRORS.TypedError(methodInfo.payload.code), + }); throw methodInfo; } + if ( + methodInfo.payload.requiredPermissions.includes('management') || + methodInfo.payload.requiredPermissions.includes('push_tx') + ) { + connectPopupActions.initiateCall({ + state: 'call-error', + callError: ERRORS.TypedError('Method_NotAllowed'), + }); + + return; + } const confirmation = createDeferred(); dispatch(extra.actions.lockDevice(true)); dispatch( connectPopupActions.initiateCall({ - method: methodInfo.payload.info, + state: 'request', + method, + methodTitle: methodInfo.payload.confirmation?.label ?? methodInfo.payload.info, + confirmLabel: methodInfo.payload.confirmation?.customConfirmButton?.label, processName, origin, confirmation, @@ -64,20 +81,20 @@ export const connectPopupCallThunkInner = createThunk< instance: device.instance, state: device.state, }, + useEmptyPassphrase: device.useEmptyPassphrase, ...payload, }); - return { - ...response, - id, - }; + // Note: for mobile this needs to be called explicitly, on desktop it's automatically handled by middleware + dispatch(deviceActions.removeButtonRequests({ device })); + + return response; } catch (error) { console.error('connectPopupCallThunk', error); return { success: false, payload: serializeError(error), - id, }; } finally { dispatch(extra.actions.lockDevice(false)); @@ -94,3 +111,69 @@ export const connectPopupCallThunk = ( ConnectPopupCallThunkParams, CustomThunkAPI > => connectPopupCallThunkInner(params) as any; + +export const connectPopupDeeplinkThunk = createThunk( + `${CONNECT_POPUP_MODULE}/deeplinkThunk`, + async ({ url }, { dispatch }) => { + try { + const parsedUrl = new URL(url); + const path = parsedUrl.pathname; + const queryParams = Object.fromEntries(parsedUrl.searchParams.entries()); + + const version = path && path.split('/').slice(-2, -1)[0]; + if ( + !queryParams?.method || + !queryParams?.params || + !queryParams?.callback || + typeof queryParams?.params !== 'string' || + typeof queryParams?.method !== 'string' || + typeof queryParams?.callback !== 'string' || + !Object.prototype.hasOwnProperty.call(TrezorConnect, queryParams?.method) + ) { + dispatch( + connectPopupActions.initiateCall({ + state: 'call-error', + callError: TypedError('Method_InvalidParameter'), + }), + ); + + return; + } + + if (!version || parseInt(version) > DEEPLINK_VERSION) { + dispatch( + connectPopupActions.initiateCall({ + state: 'call-error', + callError: TypedError('Deeplink_VersionMismatch'), + }), + ); + + return; + } + + const payload = JSON.parse(queryParams.params); + const { method, callback } = queryParams; + const callbackUrl = new URL(callback); + + const response = await dispatch( + connectPopupCallThunk({ + processName: 'deeplink', + origin: `${callbackUrl.protocol}//${callbackUrl.host}`, + // @ts-expect-error: method is dynamic + method, + payload, + }), + ).unwrap(); + + callbackUrl.searchParams.set('response', JSON.stringify(response)); + dispatch( + connectPopupActions.initiateCall({ + state: 'deeplink-callback', + callbackUrl: callbackUrl.toString(), + }), + ); + } catch (error) { + console.warn('Ignoring invalid deeplink URL', { error, url }); + } + }, +); diff --git a/suite-common/connect-popup/src/connectPopupTypes.ts b/suite-common/connect-popup/src/connectPopupTypes.ts index ed473c94bdc..ee2f3cfeb52 100644 --- a/suite-common/connect-popup/src/connectPopupTypes.ts +++ b/suite-common/connect-popup/src/connectPopupTypes.ts @@ -1,8 +1,21 @@ +import { TrezorError } from '@trezor/connect/src/constants/errors'; import { Deferred } from '@trezor/utils'; -export type ConnectPopupCall = { - method: string; - processName?: string; - origin?: string; - confirmation: Deferred; -}; +export type ConnectPopupCall = + | { + state: 'request'; + method: string; + methodTitle: string; + confirmLabel: string; + processName?: string; + origin?: string; + confirmation: Deferred; + } + | { + state: 'call-error'; + callError: TrezorError; + } + | { + state: 'deeplink-callback'; + callbackUrl: string; + }; diff --git a/suite-common/walletconnect/src/adapters/ethereum.ts b/suite-common/walletconnect/src/adapters/ethereum.ts index ce87c1e61a6..bf24fed2a82 100644 --- a/suite-common/walletconnect/src/adapters/ethereum.ts +++ b/suite-common/walletconnect/src/adapters/ethereum.ts @@ -37,7 +37,6 @@ const ethereumRequestThunk = createThunk< const account = getAccount(address); const response = await dispatch( trezorConnectPopupActions.connectPopupCallThunk({ - id: 0, method: 'ethereumSignMessage', payload: { path: account.path, @@ -62,7 +61,6 @@ const ethereumRequestThunk = createThunk< const account = getAccount(address); const response = await dispatch( trezorConnectPopupActions.connectPopupCallThunk({ - id: 0, method: 'ethereumSignTypedData', payload: { path: account.path, @@ -120,7 +118,6 @@ const ethereumRequestThunk = createThunk< }; const signResponse = await dispatch( trezorConnectPopupActions.connectPopupCallThunk({ - id: 0, method: 'ethereumSignTransaction', payload, processName: 'WalletConnect', diff --git a/suite-native/intl/src/en.ts b/suite-native/intl/src/en.ts index 64f4ec51bed..77f89aa07d9 100644 --- a/suite-native/intl/src/en.ts +++ b/suite-native/intl/src/en.ts @@ -298,6 +298,7 @@ export const en = { invalidCallback: 'Invalid callback URL', invalidParams: 'Invalid parameters from calling app', versionUnsupported: 'Unsupported version. Please update your Trezor Suite app.', + methodNotAllowed: 'Method not allowed for security reasons.', }, bottomSheets: { confirmOnDeviceMessage: 'Go to your device and verify the details of the operation.', diff --git a/suite-native/module-connect-popup/package.json b/suite-native/module-connect-popup/package.json index 567cb9b277d..60b5d225703 100644 --- a/suite-native/module-connect-popup/package.json +++ b/suite-native/module-connect-popup/package.json @@ -11,6 +11,7 @@ }, "dependencies": { "@react-navigation/native": "6.1.18", + "@reduxjs/toolkit": "1.9.5", "@suite-common/suite-types": "workspace:*", "@suite-common/wallet-core": "workspace:*", "@suite-native/atoms": "workspace:*", @@ -20,7 +21,6 @@ "@suite-native/feature-flags": "workspace:^", "@suite-native/intl": "workspace:^", "@suite-native/navigation": "workspace:*", - "@trezor/connect": "workspace:*", "@trezor/connect-mobile": "workspace:*", "expo-linking": "^7.0.5", "react": "18.2.0", diff --git a/suite-native/module-connect-popup/redux.d.ts b/suite-native/module-connect-popup/redux.d.ts new file mode 100644 index 00000000000..df9a0c3f969 --- /dev/null +++ b/suite-native/module-connect-popup/redux.d.ts @@ -0,0 +1,7 @@ +import { AsyncThunkAction } from '@reduxjs/toolkit'; + +declare module 'redux' { + export interface Dispatch { + >(thunk: TThunk): ReturnType; + } +} diff --git a/suite-native/module-connect-popup/src/hooks/useConnectMethod.ts b/suite-native/module-connect-popup/src/hooks/useConnectMethod.ts deleted file mode 100644 index 88afae04ce3..00000000000 --- a/suite-native/module-connect-popup/src/hooks/useConnectMethod.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { useEffect, useState } from 'react'; - -import TrezorConnect from '@trezor/connect'; -import type { MethodInfo } from '@trezor/connect/src/core/AbstractMethod'; - -// Load AbstractMethod from @trezor/connect based on the URL parameters -export const useConnectMethod = (popupOptions?: { method: string; params: any }) => { - const [method, setMethod] = useState(); - const [methodError, setMethodError] = useState(); - - useEffect(() => { - if (!popupOptions?.method) { - console.error('No method specified'); - setMethod(undefined); - setMethodError('No method specified'); - - return; - } - - setMethod(undefined); - setMethodError(undefined); - - const run = async () => { - try { - // @ts-expect-error method is dynamic - const methodInfo = await TrezorConnect[popupOptions.method]({ - ...popupOptions.params, - __info: true, - }); - if ( - methodInfo.payload.requiredPermissions.includes('management') || - methodInfo.payload.requiredPermissions.includes('push_tx') - ) { - setMethodError('Method requires unsafe permissions'); - - return; - } - setMethod(methodInfo.payload); - } catch (error) { - console.error('Error while getting method', error); - setMethod(undefined); - setMethodError(error.message); - } - }; - run(); - }, [popupOptions?.method, popupOptions?.params]); - - return { method, methodError }; -}; diff --git a/suite-native/module-connect-popup/src/hooks/useConnectParseParams.ts b/suite-native/module-connect-popup/src/hooks/useConnectParseParams.ts deleted file mode 100644 index 84c30da915f..00000000000 --- a/suite-native/module-connect-popup/src/hooks/useConnectParseParams.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { useMemo } from 'react'; - -import { ParsedURL } from 'expo-linking'; - -import TrezorConnect from '@trezor/connect'; -import { TrezorError, TypedError } from '@trezor/connect/src/constants/errors'; -import { DEEPLINK_VERSION } from '@trezor/connect/src/data/version'; - -type UseConnectParseParamsType = - | { - popupOptions: { - method: string; - params: any; - callback: string; - }; - parseParamsError: undefined; - } - | { - popupOptions: undefined; - parseParamsError: TrezorError; - }; - -export const useConnectParseParams = (url: ParsedURL): UseConnectParseParamsType => - useMemo(() => { - const { queryParams, path } = url; - const version = path && path.split('/').slice(-2, -1)[0]; - if ( - !queryParams?.method || - !queryParams?.params || - !queryParams?.callback || - typeof queryParams?.params !== 'string' || - typeof queryParams?.method !== 'string' || - typeof queryParams?.callback !== 'string' || - !Object.prototype.hasOwnProperty.call(TrezorConnect, queryParams?.method) - ) { - return { parseParamsError: TypedError('Method_InvalidParameter') }; - } - - if (!version || parseInt(version) > DEEPLINK_VERSION) { - return { parseParamsError: TypedError('Deeplink_VersionMismatch') }; - } - - const params = JSON.parse(queryParams.params); - const { method: methodName, callback } = queryParams; - - return { popupOptions: { method: methodName, params, callback } }; - }, [url]); diff --git a/suite-native/module-connect-popup/src/hooks/useConnectPopupNavigation.ts b/suite-native/module-connect-popup/src/hooks/useConnectPopupNavigation.ts index 0f56e42a048..b4d03a3a4f9 100644 --- a/suite-native/module-connect-popup/src/hooks/useConnectPopupNavigation.ts +++ b/suite-native/module-connect-popup/src/hooks/useConnectPopupNavigation.ts @@ -1,8 +1,10 @@ import { useEffect } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; import { useNavigation } from '@react-navigation/native'; import * as Linking from 'expo-linking'; +import { connectPopupDeeplinkThunk, selectConnectPopupCall } from '@suite-common/connect-popup'; import { isDevelopOrDebugEnv } from '@suite-native/config'; import { FeatureFlag, useFeatureFlag } from '@suite-native/feature-flags'; import { @@ -33,17 +35,21 @@ const isConnectPopupUrl = (url: string): boolean => { export const useConnectPopupNavigation = () => { const featureFlagEnabled = useFeatureFlag(FeatureFlag.IsConnectPopupEnabled); const navigation = useNavigation(); + const dispatch = useDispatch(); + const connectPopupCall = useSelector(selectConnectPopupCall); + // Handle deeplink const url = Linking.useURL(); useEffect(() => { if (!featureFlagEnabled) return; if (!url || !isConnectPopupUrl(url)) return; - try { - const parsedUrl = Linking.parse(url); - navigation.navigate(RootStackRoutes.ConnectPopup, { parsedUrl }); - } catch (error) { - console.warn('Invalid deeplink URL', { error, url }); + dispatch(connectPopupDeeplinkThunk({ url })); + }, [url, featureFlagEnabled, dispatch]); + + useEffect(() => { + if (connectPopupCall) { + navigation.navigate(RootStackRoutes.ConnectPopup); } - }, [url, navigation, featureFlagEnabled]); + }, [connectPopupCall, navigation]); }; diff --git a/suite-native/module-connect-popup/src/screens/ConnectPopupScreen.tsx b/suite-native/module-connect-popup/src/screens/ConnectPopupScreen.tsx index 6a270bb29a0..d917cce1416 100644 --- a/suite-native/module-connect-popup/src/screens/ConnectPopupScreen.tsx +++ b/suite-native/module-connect-popup/src/screens/ConnectPopupScreen.tsx @@ -1,81 +1,47 @@ -import { useCallback, useMemo, useState } from 'react'; +import { useEffect, useMemo, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { useNavigation } from '@react-navigation/native'; import * as Linking from 'expo-linking'; +import { connectPopupActions, selectConnectPopupCall } from '@suite-common/connect-popup'; import { - deviceActions, selectIsDeviceConnectedAndAuthorized, selectIsDeviceDiscoveryActive, selectIsPortfolioTrackerDevice, - selectSelectedDevice, } from '@suite-common/wallet-core'; import { Box, Button, ErrorMessage, IconButton, Loader, Text, VStack } from '@suite-native/atoms'; import { isDevelopOrDebugEnv } from '@suite-native/config'; import { DeviceManager } from '@suite-native/device-manager'; import { Translation } from '@suite-native/intl'; -import { - RootStackParamList, - RootStackRoutes, - Screen, - ScreenHeader, - StackProps, -} from '@suite-native/navigation'; -import TrezorConnect from '@trezor/connect'; +import { Screen, ScreenHeader } from '@suite-native/navigation'; import { ButtonRequestsOverlay } from '../components/ButtonRequestsOverlay'; -import { ConnectPopupDebugOptions } from '../components/ConnectPopupDebugOptions'; -import { useConnectMethod } from '../hooks/useConnectMethod'; -import { useConnectParseParams } from '../hooks/useConnectParseParams'; -import { callbackURLOrigin } from '../utils/callbackURLOrigin'; - -export const ConnectPopupScreen = ({ - route, -}: StackProps) => { + +export const ConnectPopupScreen = () => { const navigation = useNavigation(); const dispatch = useDispatch(); - const device = useSelector(selectSelectedDevice); const deviceConnectedAndAuthorized = useSelector(selectIsDeviceConnectedAndAuthorized); const isPortfolioTrackerDevice = useSelector(selectIsPortfolioTrackerDevice); const validDevice = deviceConnectedAndAuthorized && !isPortfolioTrackerDevice; const discoveryActive = useSelector(selectIsDeviceDiscoveryActive); - + const popupCall = useSelector(selectConnectPopupCall); const [showDebug, setShowDebug] = useState(false); - const [callResult, setCallResult] = useState(); - const [loading, setLoading] = useState(false); - - const { popupOptions, parseParamsError } = useConnectParseParams(route.params.parsedUrl); - const { method, methodError } = useConnectMethod(popupOptions); - - const callDevice = useCallback(async () => { - if (!popupOptions || !device) return; - - setLoading(true); - // @ts-expect-error method is dynamic - const response = await TrezorConnect[popupOptions.method]({ - ...popupOptions.params, - device: { - path: device.path, - instance: device.instance, - state: device.state, - }, - useEmptyPassphrase: device.useEmptyPassphrase, - }); - setCallResult(response); - dispatch(deviceActions.removeButtonRequests({ device })); - const callbackUrl = new URL(popupOptions.callback); - callbackUrl.searchParams.set('response', JSON.stringify(response)); - Linking.openURL(callbackUrl.toString()); - setLoading(false); - if (navigation.canGoBack()) { - navigation.goBack(); + + useEffect(() => { + if (popupCall?.state === 'deeplink-callback') { + Linking.openURL(popupCall.callbackUrl); + if (navigation.canGoBack()) { + navigation.goBack(); + } } - }, [popupOptions, dispatch, device, navigation]); + }, [popupCall, navigation]); const mainView = useMemo(() => { - if (loading) { + const onConfirm = () => dispatch(connectPopupActions.approveCall()); + + if (!popupCall) { return ( - - {method.confirmation?.label ?? method.info} - + {popupCall.methodTitle} {': '} - {callbackOrigin} + {popupCall.origin} - @@ -137,24 +100,21 @@ export const ConnectPopupScreen = ({ ); } - if (parseParamsError) { - return ( - - } - /> - ); - } + if (popupCall.state === 'call-error') { + const getTranslationId = () => { + switch (popupCall.callError.code) { + case 'Deeplink_VersionMismatch': + return 'moduleConnectPopup.errors.versionUnsupported'; + case 'Method_NotAllowed': + return 'moduleConnectPopup.errors.methodNotAllowed'; + case 'Device_NotFound': + return 'moduleConnectPopup.errors.deviceNotConnected'; + default: + return 'moduleConnectPopup.errors.invalidParams'; + } + }; - if (methodError) { - return ; + return } />; } return ( @@ -171,16 +131,7 @@ export const ConnectPopupScreen = ({ /> ); } - }, [ - validDevice, - method, - popupOptions, - parseParamsError, - methodError, - loading, - discoveryActive, - callDevice, - ]); + }, [validDevice, popupCall, discoveryActive, dispatch]); return ( - - - Device: {JSON.stringify(device, null, 2)} - Params: {JSON.stringify(route.params.parsedUrl.queryParams)} - Call result: {JSON.stringify(callResult)} - ); }; diff --git a/suite-native/module-connect-popup/src/utils/callbackURLOrigin.ts b/suite-native/module-connect-popup/src/utils/callbackURLOrigin.ts deleted file mode 100644 index 8654f5a6bbc..00000000000 --- a/suite-native/module-connect-popup/src/utils/callbackURLOrigin.ts +++ /dev/null @@ -1,9 +0,0 @@ -export const callbackURLOrigin = (fullUrl: string) => { - try { - const url = new URL(fullUrl); - - return `${url.protocol}//${url.host}`; - } catch { - return undefined; - } -}; diff --git a/suite-native/module-connect-popup/tsconfig.json b/suite-native/module-connect-popup/tsconfig.json index c5028852616..c3c0c910538 100644 --- a/suite-native/module-connect-popup/tsconfig.json +++ b/suite-native/module-connect-popup/tsconfig.json @@ -15,7 +15,6 @@ { "path": "../feature-flags" }, { "path": "../intl" }, { "path": "../navigation" }, - { "path": "../../packages/connect" }, { "path": "../../packages/connect-mobile" } diff --git a/suite-native/navigation/package.json b/suite-native/navigation/package.json index f974d87943f..0b96488db32 100644 --- a/suite-native/navigation/package.json +++ b/suite-native/navigation/package.json @@ -27,7 +27,6 @@ "@trezor/styles": "workspace:*", "@trezor/theme": "workspace:*", "expo-linear-gradient": "14.0.1", - "expo-linking": "^7.0.5", "expo-navigation-bar": "^4.0.2", "expo-system-ui": "^4.0.2", "react": "18.2.0", diff --git a/suite-native/navigation/src/navigators.ts b/suite-native/navigation/src/navigators.ts index a6b901e2af3..d155b94ec4d 100644 --- a/suite-native/navigation/src/navigators.ts +++ b/suite-native/navigation/src/navigators.ts @@ -1,5 +1,4 @@ import { NavigatorScreenParams } from '@react-navigation/native'; -import { ParsedURL } from 'expo-linking'; import { RequireAllOrNone } from 'type-fest'; import { AccountType, NetworkSymbol } from '@suite-common/wallet-config'; @@ -221,9 +220,7 @@ export type RootStackParamList = { [RootStackRoutes.ReceiveStack]: NavigatorScreenParams; [RootStackRoutes.SendStack]: NavigatorScreenParams; [RootStackRoutes.CoinEnablingInit]: undefined; - [RootStackRoutes.ConnectPopup]: { - parsedUrl: ParsedURL; - }; + [RootStackRoutes.ConnectPopup]: undefined; [RootStackRoutes.SettingsScreenStack]: NavigatorScreenParams; [RootStackRoutes.DeviceCompromisedModalScreen]: undefined; }; diff --git a/suite-native/state/src/reducers.ts b/suite-native/state/src/reducers.ts index 7f2a8c1f204..68f1d9db7b0 100644 --- a/suite-native/state/src/reducers.ts +++ b/suite-native/state/src/reducers.ts @@ -1,6 +1,7 @@ import { combineReducers } from '@reduxjs/toolkit'; import { prepareAnalyticsReducer } from '@suite-common/analytics'; +import { prepareConnectPopupReducer } from '@suite-common/connect-popup'; import { prepareFirmwareReducer } from '@suite-common/firmware'; import { logsSlice } from '@suite-common/logger'; import { @@ -61,6 +62,7 @@ const tokenDefinitionsReducer = prepareTokenDefinitionsReducer(extraDependencies const sendFormReducer = sendFormSlice.prepareReducer(extraDependencies); const stakeReducer = prepareStakeReducer(extraDependencies); const firmwareReducer = prepareFirmwareReducer(extraDependencies); +const connectPopupReducer = prepareConnectPopupReducer(extraDependencies); export const prepareRootReducers = async () => { const appSettingsPersistedReducer = await preparePersistReducer({ @@ -82,6 +84,7 @@ export const prepareRootReducers = async () => { send: sendFormReducer, fees: feesReducer, stake: stakeReducer, + connectPopup: connectPopupReducer, }); const walletPersistedReducer = await preparePersistReducer({ diff --git a/yarn.lock b/yarn.lock index 5204697d8e6..df86eb50732 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10298,6 +10298,11 @@ __metadata: "@trezor/utils": "workspace:*" redux-mock-store: "npm:^1.5.4" redux-thunk: "npm:^2.4.2" + peerDependencies: + "@trezor/suite-desktop-api": "workspace:*" + peerDependenciesMeta: + "@trezor/suite-desktop-api": + optional: true languageName: unknown linkType: soft @@ -11546,6 +11551,7 @@ __metadata: resolution: "@suite-native/module-connect-popup@workspace:suite-native/module-connect-popup" dependencies: "@react-navigation/native": "npm:6.1.18" + "@reduxjs/toolkit": "npm:1.9.5" "@suite-common/suite-types": "workspace:*" "@suite-common/wallet-core": "workspace:*" "@suite-native/atoms": "workspace:*" @@ -11555,7 +11561,6 @@ __metadata: "@suite-native/feature-flags": "workspace:^" "@suite-native/intl": "workspace:^" "@suite-native/navigation": "workspace:*" - "@trezor/connect": "workspace:*" "@trezor/connect-mobile": "workspace:*" expo-linking: "npm:^7.0.5" react: "npm:18.2.0" @@ -11836,7 +11841,6 @@ __metadata: "@trezor/styles": "workspace:*" "@trezor/theme": "workspace:*" expo-linear-gradient: "npm:14.0.1" - expo-linking: "npm:^7.0.5" expo-navigation-bar: "npm:^4.0.2" expo-system-ui: "npm:^4.0.2" react: "npm:18.2.0"