diff --git a/packages/suite/src/components/suite/Preloader/__tests__/Preloader.test.tsx b/packages/suite/src/components/suite/Preloader/__tests__/Preloader.test.tsx index f1fd1ce740ff..7c72bb5fac74 100644 --- a/packages/suite/src/components/suite/Preloader/__tests__/Preloader.test.tsx +++ b/packages/suite/src/components/suite/Preloader/__tests__/Preloader.test.tsx @@ -20,6 +20,18 @@ jest.mock('cross-fetch', () => ({ default: () => Promise.resolve({ ok: false }), })); +// mock desktopApi +jest.mock('@trezor/suite-desktop-api', () => ({ + __esModule: true, + desktopApi: { + getBridgeStatus: () => + Promise.resolve({ success: true, payload: { service: true, process: true } }), + getBridgeSettings: () => Promise.resolve({ success: true, payload: { enabled: true } }), + on: (_event: string, _cb: any) => {}, + removeAllListeners: (_event: string) => {}, + }, +})); + // jest.mock('@firmware-components/ReconnectDevicePrompt', () => ({ // __esModule: true, // export as module // default: ({ children }: any) =>
{children}
, @@ -230,7 +242,7 @@ describe('Preloader component', () => { const { unmount } = renderWithProviders(store, ); expect(findByTestId('@connect-device-prompt')).not.toBeNull(); - expect(findByTestId('@connect-device-prompt/unreadable-hid')).not.toBeNull(); + expect(findByTestId('@connect-device-prompt/unreadable-unknown')).not.toBeNull(); unmount(); }); diff --git a/packages/suite/src/components/suite/PrerequisitesGuide/DeviceUnreadable.tsx b/packages/suite/src/components/suite/PrerequisitesGuide/DeviceUnreadable.tsx index 6bdfddd9b847..0efddc2c23c3 100644 --- a/packages/suite/src/components/suite/PrerequisitesGuide/DeviceUnreadable.tsx +++ b/packages/suite/src/components/suite/PrerequisitesGuide/DeviceUnreadable.tsx @@ -2,16 +2,18 @@ import { useState, MouseEvent } from 'react'; import { Button } from '@trezor/components'; import { desktopApi } from '@trezor/suite-desktop-api'; import { isDesktop, isLinux } from '@trezor/env-utils'; +import { notificationsActions } from '@suite-common/toast-notifications'; +import { selectDevice } from '@suite-common/wallet-core'; + import { Translation, TroubleshootingTips, UdevDownload } from 'src/components/suite'; import { - TROUBLESHOOTING_TIP_BRIDGE_STATUS, TROUBLESHOOTING_TIP_SUITE_DESKTOP, - TROUBLESHOOTING_TIP_CABLE, - TROUBLESHOOTING_TIP_USB, TROUBLESHOOTING_TIP_DIFFERENT_COMPUTER, + TROUBLESHOOTING_TIP_UNREADABLE_HID, + TROUBLESHOOTING_TIP_SUITE_DESKTOP_TOGGLE_BRIDGE, + TROUBLESHOOTING_TIP_RECONNECT, } from 'src/components/suite/troubleshooting/tips'; -import { useDispatch } from 'src/hooks/suite'; -import { notificationsActions } from '@suite-common/toast-notifications'; +import { useSelector, useDispatch } from 'src/hooks/suite'; import type { TrezorDevice } from 'src/types/suite'; // linux web @@ -99,28 +101,44 @@ const UdevDesktop = () => { interface DeviceUnreadableProps { device?: TrezorDevice; // this should be actually UnreadableDevice, but it is not worth type casting - isWebUsbTransport: boolean; } -// We don't really know what happened, show some generic help and provide link to contact a support -export const DeviceUnreadable = ({ device, isWebUsbTransport }: DeviceUnreadableProps) => { - if (isWebUsbTransport) { - // only install bridge will help (webusb + HID device) - return ( - } - items={[TROUBLESHOOTING_TIP_BRIDGE_STATUS, TROUBLESHOOTING_TIP_SUITE_DESKTOP]} - offerWebUsb - data-testid="@connect-device-prompt/unreadable-hid" - /> - ); - } +/** + * Device was detected but @trezor/connect was not able to communicate with it. Reasons could be: + * - initial read from device (GetFeatures) failed because of some de-synchronization or clash with another application + * - device can't be communicated with using currently used transport (eg. hid / node bridge + webusb) + * - missing udev rule on linux + */ +export const DeviceUnreadable = ({ device }: DeviceUnreadableProps) => { + const selectedDevice = useSelector(selectDevice); // this error is dispatched by trezord when udev rules are missing if (isLinux() && device?.error === 'LIBUSB_ERROR_ACCESS') { return <> {isDesktop() ? : }; } + // generic troubleshooting tips + const items = [ + // closing other apps and reloading should be the first step. Either we might have made a bug and let two apps to talk + // to device at the same time or there might be another application in the wild not really playing according to our rules + TROUBLESHOOTING_TIP_RECONNECT, + // if on web - try installing desktop. this takes you to using bridge which should be more powerful than WebUSB + TROUBLESHOOTING_TIP_SUITE_DESKTOP, + // unfortunately we have seen reports that even old bridge might not be enough for some Windows users. So the only chance + // is using another computer, or maybe it would be better to say another OS + TROUBLESHOOTING_TIP_DIFFERENT_COMPUTER, + ]; + + // only for unreadable HID devices + if (selectedDevice?.transportDescriptorType === 0) { + // If even this did not work, go to support or knowledge base + // 'If the last time you updated your device firmware was in 2019 and earlier please follow instructions in the knowledge base', + items.push(TROUBLESHOOTING_TIP_UNREADABLE_HID); + // you might have a very old device which is no longer supported current bridge + // if on desktop - try toggling between the 2 bridges we have available + items.push(TROUBLESHOOTING_TIP_SUITE_DESKTOP_TOGGLE_BRIDGE); + } + return ( } - items={[ - TROUBLESHOOTING_TIP_CABLE, - TROUBLESHOOTING_TIP_USB, - TROUBLESHOOTING_TIP_DIFFERENT_COMPUTER, - ]} - offerWebUsb={isWebUsbTransport} + items={items} data-testid="@connect-device-prompt/unreadable-unknown" /> ); diff --git a/packages/suite/src/components/suite/PrerequisitesGuide/PrerequisitesGuide.tsx b/packages/suite/src/components/suite/PrerequisitesGuide/PrerequisitesGuide.tsx index 799e663cd56f..e4818461649e 100644 --- a/packages/suite/src/components/suite/PrerequisitesGuide/PrerequisitesGuide.tsx +++ b/packages/suite/src/components/suite/PrerequisitesGuide/PrerequisitesGuide.tsx @@ -61,9 +61,7 @@ export const PrerequisitesGuide = ({ allowSwitchDevice }: PrerequisitesGuideProp case 'device-unacquired': return ; case 'device-unreadable': - return ( - - ); + return ; case 'device-unknown': return ; case 'device-seedless': diff --git a/packages/suite/src/components/suite/PrerequisitesGuide/Transport.tsx b/packages/suite/src/components/suite/PrerequisitesGuide/Transport.tsx index c88fc3d95ed2..7832438f60e6 100644 --- a/packages/suite/src/components/suite/PrerequisitesGuide/Transport.tsx +++ b/packages/suite/src/components/suite/PrerequisitesGuide/Transport.tsx @@ -1,23 +1,28 @@ import { Translation, TroubleshootingTips } from 'src/components/suite'; + import { TROUBLESHOOTING_TIP_SUITE_DESKTOP, TROUBLESHOOTING_TIP_RESTART_COMPUTER, TROUBLESHOOTING_TIP_WEBUSB_ENVIRONMENT, } from 'src/components/suite/troubleshooting/tips'; -export const Transport = () => ( - // No transport layer (bridge/webUSB) is available - // On web it makes sense to - // - offer downloading Trezor Suite desktop, or - // - use a browser that supports WebUSB - // Desktop app should have Bridge transport layer available as it is built-in, if it is not available we fucked up something. - } - items={[ - TROUBLESHOOTING_TIP_WEBUSB_ENVIRONMENT, - TROUBLESHOOTING_TIP_SUITE_DESKTOP, - TROUBLESHOOTING_TIP_RESTART_COMPUTER, - ]} - data-testid="@connect-device-prompt/bridge-not-running" - /> -); +export const Transport = () => { + const items = [ + TROUBLESHOOTING_TIP_WEBUSB_ENVIRONMENT, + TROUBLESHOOTING_TIP_SUITE_DESKTOP, + TROUBLESHOOTING_TIP_RESTART_COMPUTER, + ]; + + return ( + // No transport layer (bridge/webUSB) is available + // On web it makes sense to + // - offer downloading Trezor Suite desktop, or + // - use a browser that supports WebUSB + // Desktop app should have Bridge transport layer available as it is built-in, if it is not available we fucked up something. + } + items={items} + data-testid="@connect-device-prompt/bridge-not-running" + /> + ); +}; diff --git a/packages/suite/src/components/suite/troubleshooting/tips/BridgeTip.tsx b/packages/suite/src/components/suite/troubleshooting/tips/BridgeTip.tsx index 321295e02cfa..0e3180a70ee9 100644 --- a/packages/suite/src/components/suite/troubleshooting/tips/BridgeTip.tsx +++ b/packages/suite/src/components/suite/troubleshooting/tips/BridgeTip.tsx @@ -5,8 +5,10 @@ import { typography } from '@trezor/theme'; import { TrezorLink } from 'src/components/suite'; import { Translation } from 'src/components/suite/Translation'; import { useOpenSuiteDesktop } from 'src/hooks/suite/useOpenSuiteDesktop'; +import { useBridgeDesktopApi } from 'src/hooks/suite/useBridgeDesktopApi'; +import { useSelector } from 'src/hooks/suite'; -const Wrapper = styled.div` +export const Wrapper = styled.div` a { ${typography.hint}; } @@ -45,3 +47,34 @@ export const BridgeStatus = () => ( /> ); + +export const BridgeToggle = () => { + const { changeBridgeSettings, bridgeSettings } = useBridgeDesktopApi(); + const transport = useSelector(state => state.suite.transport); + + if (!bridgeSettings) return null; + + return ( + + ( + { + changeBridgeSettings({ + ...bridgeSettings, + legacy: !bridgeSettings?.legacy, + }); + }} + > + {chunks} + + ), + }} + /> + + ); +}; diff --git a/packages/suite/src/components/suite/troubleshooting/tips/index.tsx b/packages/suite/src/components/suite/troubleshooting/tips/index.tsx index afcf681a79d7..81b2fe205551 100644 --- a/packages/suite/src/components/suite/troubleshooting/tips/index.tsx +++ b/packages/suite/src/components/suite/troubleshooting/tips/index.tsx @@ -1,8 +1,10 @@ import { isWeb, isDesktop, isLinux, isAndroid } from '@trezor/env-utils'; +import { TREZOR_SUPPORT_DEVICE_URL } from '@trezor/urls'; +import { TrezorLink } from 'src/components/suite'; import { Translation } from 'src/components/suite/Translation'; -import { BridgeStatus, SuiteDesktopTip } from './BridgeTip'; +import { BridgeStatus, SuiteDesktopTip, BridgeToggle, Wrapper } from './BridgeTip'; import { UdevDescription } from './UdevDescription'; export const TROUBLESHOOTING_TIP_BRIDGE_STATUS = { @@ -19,6 +21,25 @@ export const TROUBLESHOOTING_TIP_WEBUSB_ENVIRONMENT = { hide: !isWeb(), }; +export const TROUBLESHOOTING_TIP_UNREADABLE_HID = { + key: 'unreadable-hid', + heading: , + description: ( + + ( + + {chunks} + + ), + }} + /> + + ), +}; + export const TROUBLESHOOTING_TIP_SUITE_DESKTOP = { key: 'suite-desktop', heading: , @@ -26,6 +47,13 @@ export const TROUBLESHOOTING_TIP_SUITE_DESKTOP = { hide: !isWeb(), }; +export const TROUBLESHOOTING_TIP_SUITE_DESKTOP_TOGGLE_BRIDGE = { + key: 'suite-desktop', + heading: , + description: , + hide: isWeb() || isAndroid(), +}; + export const TROUBLESHOOTING_TIP_CABLE = { key: 'cable', heading: , diff --git a/packages/suite/src/support/messages.ts b/packages/suite/src/support/messages.ts index 41aaf60d1e24..423f2204a697 100644 --- a/packages/suite/src/support/messages.ts +++ b/packages/suite/src/support/messages.ts @@ -7147,6 +7147,15 @@ export default defineMessages({ 'Only Chromium-based browsers currently allow direct communication with USB devices.', id: 'TR_TROUBLESHOOTING_TIP_BROWSER_WEBUSB_DESCRIPTION', }, + TR_TROUBLESHOOTING_TIP_UNREADABLE_HID_TITLE: { + defaultMessage: 'You may be using a very old Trezor model', + id: 'TR_TROUBLESHOOTING_TIP_UNREADABLE_HID_TITLE', + }, + TR_TROUBLESHOOTING_TIP_UNREADABLE_HID_DESCRIPTION: { + defaultMessage: + 'If the last time you updated your device firmware was in 2019 and earlier please follow instructions in the knowledge base', + id: 'TR_TROUBLESHOOTING_TIP_UNREADABLE_HID_DESCRIPTION', + }, TR_TROUBLESHOOTING_TIP_SUITE_DESKTOP_TITLE: { id: 'TR_TROUBLESHOOTING_TIP_SUITE_DESKTOP_TITLE', defaultMessage: 'Use the Trezor Suite desktop app', @@ -7155,6 +7164,15 @@ export default defineMessages({ id: 'TR_TROUBLESHOOTING_TIP_SUITE_DESKTOP_DESCRIPTION', defaultMessage: 'Run the Trezor Suite desktop app', }, + TR_TROUBLESHOOTING_TIP_SUITE_DESKTOP_TOGGLE_BRIDGE_TITLE: { + id: 'TR_TROUBLESHOOTING_TIP_SUITE_DESKTOP_TOGGLE_BRIDGE_TITLE', + defaultMessage: 'Use another version of Trezor Bridge', + }, + TR_TROUBLESHOOTING_TIP_SUITE_DESKTOP_TOGGLE_BRIDGE_DESCRIPTION: { + id: 'TR_TROUBLESHOOTING_TIP_SUITE_DESKTOP_TOGGLE_BRIDGE_DESCRIPTION', + defaultMessage: + 'Click to toggle an alternative bridge implementation. Current version: ({currentVersion})', + }, TR_TROUBLESHOOTING_TIP_UDEV_INSTALL_DESCRIPTION: { id: 'TR_TROUBLESHOOTING_TIP_UDEV_INSTALL_DESCRIPTION', defaultMessage: @@ -7173,6 +7191,7 @@ export default defineMessages({ 'After closing other browser tabs and windows, try quitting and reopening Trezor Suite.', id: 'TR_TROUBLESHOOTING_CLOSE_TABS_DESCRIPTION_DESKTOP', }, + TR_TROUBLESHOOTING_TIP_CABLE_TITLE: { id: 'TR_TROUBLESHOOTING_TIP_CABLE_TITLE', defaultMessage: 'Try a different cable', @@ -7208,11 +7227,6 @@ export default defineMessages({ defaultMessage: 'Restarting your computer may fix the communication issue between your browser and device.', }, - TR_TROUBLESHOOTING_UNREADABLE_WEBUSB: { - id: 'TR_TROUBLESHOOTING_UNREADABLE_WEBUSB', - defaultMessage: - "Your device is connected properly, but your browser can't communicate with it at the moment. You need to install Trezor Bridge.", - }, TR_TROUBLESHOOTING_UNREADABLE_UDEV: { id: 'TR_TROUBLESHOOTING_UNREADABLE_UDEV', defaultMessage: 'Missing udev rules',