UNPKG

@ledgerhq/live-common

Version:
106 lines 4.61 kB
import { Observable, concat, concatWith, from, of, throwError } from "rxjs"; import { concatMap, catchError, delay } from "rxjs/operators"; import { TransportStatusError, DeviceOnDashboardExpected, StatusCodes, LockedDeviceError, } from "@ledgerhq/errors"; import { isCharonSupported } from "@ledgerhq/device-core"; import { identifyTargetId } from "@ledgerhq/devices"; import { PrepareConnectManagerDeviceAction } from "@ledgerhq/live-dmk-shared"; import { listAppsUseCase } from "../device/use-cases/listAppsUseCase"; import { withDevice } from "./deviceAccess"; import getDeviceInfo from "./getDeviceInfo"; import getAppAndVersion from "./getAppAndVersion"; import { isDashboardName } from "./isDashboardName"; import { DeviceNotOnboarded } from "../errors"; import attemptToQuitApp from "./attemptToQuitApp"; import { PrepareConnectManagerEventMapper } from "./connectManagerEventMapper"; import { extractOnboardingState, OnboardingStep } from "./extractOnboardingState"; import { isDmkTransport } from "./dmkUtils"; const cmd = (transport, { request }) => new Observable(o => { const timeoutSub = of({ type: "unresponsiveDevice", }) .pipe(delay(1000)) .subscribe(e => o.next(e)); const sub = from(getDeviceInfo(transport)) .pipe(concatMap(deviceInfo => { timeoutSub.unsubscribe(); if (!deviceInfo.onboarded && !deviceInfo.isRecoveryMode) { throw new DeviceNotOnboarded(); } if (deviceInfo.isBootloader) { return of({ type: "bootloader", deviceInfo, }); } if (deviceInfo.isOSU) { return of({ type: "osu", deviceInfo, }); } if (isCharonSupported(deviceInfo.seVersion ?? "", identifyTargetId(deviceInfo.seTargetId ?? 0)?.id)) { const onboardingState = extractOnboardingState(deviceInfo.seFlags, deviceInfo.charonState); if (onboardingState.currentOnboardingStep === OnboardingStep.BackupCharon) { throw new DeviceNotOnboarded(); } } return concat(of({ type: "listingApps", deviceInfo, }), listAppsUseCase(transport, deviceInfo)); }), catchError((e) => { if (e instanceof LockedDeviceError) { return of({ type: "lockedDevice", }); } else if (e instanceof DeviceOnDashboardExpected || (e && e instanceof TransportStatusError && [ StatusCodes.CLA_NOT_SUPPORTED, StatusCodes.INS_NOT_SUPPORTED, StatusCodes.UNKNOWN_APDU, 0x6e01, // No StatusCodes definition 0x6d01, // No StatusCodes definition ].includes(e.statusCode))) { return from(getAppAndVersion(transport)).pipe(concatMap(appAndVersion => { return !request?.autoQuitAppDisabled && !isDashboardName(appAndVersion.name) ? attemptToQuitApp(transport, appAndVersion) : of({ type: "appDetected", }); })); } return throwError(() => e); })) .subscribe(o); return () => { timeoutSub.unsubscribe(); sub.unsubscribe(); }; }); export default function connectManagerFactory({ isLdmkConnectAppEnabled, } = { isLdmkConnectAppEnabled: false }) { if (!isLdmkConnectAppEnabled) { return ({ deviceId, deviceName, request }) => withDevice(deviceId, deviceName ? { matchDeviceByName: deviceName } : undefined)(transport => cmd(transport, { deviceId, deviceName, request })); } return ({ deviceId, deviceName, request }) => withDevice(deviceId, deviceName ? { matchDeviceByName: deviceName } : undefined)(transport => { if (!isDmkTransport(transport)) { return cmd(transport, { deviceId, deviceName, request }); } const { dmk, sessionId } = transport; const deviceAction = new PrepareConnectManagerDeviceAction({ input: { unlockTimeout: 0, // Expect to fail immediately when device is locked }, }); const observable = dmk.executeDeviceAction({ sessionId, deviceAction, }); return new PrepareConnectManagerEventMapper(observable) .map() .pipe(concatWith(cmd(transport, { deviceId, deviceName, request }))); }); } //# sourceMappingURL=connectManager.js.map