UNPKG

@ledgerhq/live-common

Version:
113 lines 5.13 kB
import { useCallback, useEffect, useState, useRef } from "react"; import { UnresponsiveDeviceError, UserRefusedAllowManager } from "@ledgerhq/errors"; import { getGenuineCheckFromDeviceId as defaultGetGenuineCheckFromDeviceId } from "../getGenuineCheckFromDeviceId"; import { isDmkError } from "../../deviceSDK/tasks/core"; const SOCKET_EVENT_PAYLOAD_GENUINE = "0000"; const clearTimeoutRef = (timeoutRef) => { if (timeoutRef.current) { clearTimeout(timeoutRef.current); timeoutRef.current = null; } }; const isDmkDeviceDisconnectedError = (e) => isDmkError(e) && e._tag === "DeviceDisconnectedWhileSendingError"; /** * Hook to check that a device is genuine * It replaces a DeviceAction if we're only interested in getting the genuine check * @param getGenuineCheckFromDeviceId An optional function to get a genuine check for a given device id, * by default set to live-common/hw/getGenuineCheckFromDeviceId. * This dependency injection is needed for LLD to have the hook working on the internal thread * @param isHookEnabled A boolean to enable (true, default value) or disable (false) the hook * @param deviceId A device id, or an empty string if device is usb plugged * @param lockedDeviceTimeoutMs Time of no response from device after which the device is considered locked, in ms. Default 1000ms. * @param permissionTimeoutMs Time to wait for a device response to a permission request, in ms. Default 60s. * @returns An object containing: * - genuineState: the current GenuineState * - devicePermissionState: the current DevicePermissionState * - error: any error that occurred during the genuine check, or null */ export const useGenuineCheck = ({ getGenuineCheckFromDeviceId = defaultGetGenuineCheckFromDeviceId, isHookEnabled = true, deviceId, lockedDeviceTimeoutMs = 1000, permissionTimeoutMs = 60 * 1000, }) => { const [genuineState, setGenuineState] = useState("unchecked"); const [devicePermissionState, setDevicePermissionState] = useState("unrequested"); const [error, setError] = useState(null); const timeoutRef = useRef(null); const resetGenuineCheckState = useCallback(() => { setDevicePermissionState("unrequested"); setGenuineState("unchecked"); setError(null); }, []); useEffect(() => { if (!isHookEnabled) { return; } const sub = getGenuineCheckFromDeviceId({ deviceId, lockedDeviceTimeoutMs, }).subscribe({ next: ({ socketEvent, lockedDevice }) => { if (socketEvent) { switch (socketEvent.type) { case "device-permission-requested": setDevicePermissionState("requested"); timeoutRef.current = setTimeout(() => { setError(new UnresponsiveDeviceError()); clearTimeoutRef(timeoutRef); }, permissionTimeoutMs); break; case "device-permission-granted": clearTimeoutRef(timeoutRef); setDevicePermissionState("granted"); break; case "result": clearTimeoutRef(timeoutRef); if (socketEvent.payload === SOCKET_EVENT_PAYLOAD_GENUINE) { setGenuineState("genuine"); } else { setGenuineState("non-genuine"); } break; } } else { clearTimeoutRef(timeoutRef); // If no socketEvent, the device is locked or has been unlocked if (lockedDevice) { setDevicePermissionState("unlock-needed"); } else { setDevicePermissionState("unlocked"); } } }, error: (e) => { clearTimeoutRef(timeoutRef); if (e instanceof UserRefusedAllowManager) { setDevicePermissionState("refused"); } else if (e instanceof Error || isDmkDeviceDisconnectedError(e)) { // Probably an error of type DisconnectedDeviceDuringOperation or something else setError(e); } else { setError(new Error(`Unknown error: ${e}`)); } }, }); return () => { sub.unsubscribe(); }; }, [ isHookEnabled, deviceId, lockedDeviceTimeoutMs, getGenuineCheckFromDeviceId, permissionTimeoutMs, ]); return { genuineState, devicePermissionState, error, resetGenuineCheckState, }; }; //# sourceMappingURL=useGenuineCheck.js.map