Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🏗️ [Support] Request device access within HWDeviceProvider #7440

Merged
merged 16 commits into from
Aug 8, 2024
Merged
8 changes: 8 additions & 0 deletions .changeset/rude-moons-do.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"ledger-live-desktop": minor
"live-mobile": minor
"@ledgerhq/trustchain": minor
"@ledgerhq/web-tools": minor
---

Request device access within `HWDeviceProvider`
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,8 @@ import { memberCredentialsSelector, setTrustchain } from "@ledgerhq/trustchain/s
import { useDispatch, useSelector } from "react-redux";
import { setFlow } from "~/renderer/actions/walletSync";
import { Flow, Step } from "~/renderer/reducers/walletSync";
import { useTrustchainSdk, runWithDevice } from "./useTrustchainSdk";
import {
MemberCredentials,
TrustchainResult,
TrustchainResultType,
} from "@ledgerhq/trustchain/types";
import { useTrustchainSdk } from "./useTrustchainSdk";
import { TrustchainResult, TrustchainResultType } from "@ledgerhq/trustchain/types";
import { useCallback, useEffect, useRef, useState } from "react";

export function useAddMember({ device }: { device: Device | null }) {
Expand Down Expand Up @@ -52,24 +48,24 @@ export function useAddMember({ device }: { device: Device | null }) {
};

useEffect(() => {
if (!deviceRef.current) {
handleMissingDevice();
}

const addMember = async () => {
try {
await runWithDevice(deviceRef.current?.deviceId, async transport => {
const trustchainResult = await sdkRef.current.getOrCreateTrustchain(
transport,
memberCredentialsRef.current as MemberCredentials,
{
onStartRequestUserInteraction: () => setUserDeviceInteraction(true),
onEndRequestUserInteraction: () => setUserDeviceInteraction(false),
},
);
if (!deviceRef.current) {
return handleMissingDevice();
}
if (!memberCredentialsRef.current) {
throw new Error("memberCredentials is not set");
}
const trustchainResult = await sdkRef.current.getOrCreateTrustchain(
deviceRef.current.deviceId,
memberCredentialsRef.current,
{
onStartRequestUserInteraction: () => setUserDeviceInteraction(true),
onEndRequestUserInteraction: () => setUserDeviceInteraction(false),
},
);

transitionToNextScreen(trustchainResult);
});
transitionToNextScreen(trustchainResult);
} catch (error) {
setError(error as Error);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import {
import { useDispatch, useSelector } from "react-redux";
import { setFlow } from "~/renderer/actions/walletSync";
import { Flow, Step } from "~/renderer/reducers/walletSync";
import { useTrustchainSdk, runWithDevice } from "./useTrustchainSdk";
import { TrustchainMember, Trustchain, MemberCredentials } from "@ledgerhq/trustchain/types";
import { useTrustchainSdk } from "./useTrustchainSdk";
import { TrustchainMember, Trustchain } from "@ledgerhq/trustchain/types";
import { useCallback, useEffect, useRef, useState } from "react";
import { TrustchainNotAllowed } from "@ledgerhq/trustchain/errors";

Expand Down Expand Up @@ -51,20 +51,24 @@ export function useRemoveMember({ device, member }: Props) {
const removeMember = useCallback(
async (member: TrustchainMember) => {
try {
await runWithDevice(deviceRef.current?.deviceId, async transport => {
const newTrustchain = await sdkRef.current.removeMember(
transport,
trustchainRef.current as Trustchain,
memberCredentialsRef.current as MemberCredentials,
member,
{
onStartRequestUserInteraction: () => setUserDeviceInteraction(true),
onEndRequestUserInteraction: () => setUserDeviceInteraction(false),
},
);
if (!deviceRef.current) {
throw new Error("Device not found");
}
if (!trustchainRef.current || !memberCredentialsRef.current) {
throw new Error("trustchain or memberCredentials is not set");
}
const newTrustchain = await sdkRef.current.removeMember(
deviceRef.current.deviceId,
trustchainRef.current,
memberCredentialsRef.current,
member,
{
onStartRequestUserInteraction: () => setUserDeviceInteraction(true),
onEndRequestUserInteraction: () => setUserDeviceInteraction(false),
},
);

transitionToNextScreen(newTrustchain);
});
transitionToNextScreen(newTrustchain);
} catch (error) {
if (error instanceof Error) setError(error);
if (error instanceof TrustchainNotAllowed) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import os from "os";
import { from, lastValueFrom } from "rxjs";
import { useMemo } from "react";
import { getEnv } from "@ledgerhq/live-env";
import { getSdk } from "@ledgerhq/trustchain/index";
import { withDevice } from "@ledgerhq/live-common/hw/deviceAccess";
import Transport from "@ledgerhq/hw-transport";
import { trustchainLifecycle } from "@ledgerhq/live-wallet/walletsync/index";
import { useStore } from "react-redux";
import { walletSelector } from "~/renderer/reducers/wallet";
Expand All @@ -13,13 +11,6 @@ import { TrustchainSDK } from "@ledgerhq/trustchain/types";
import { useFeature } from "@ledgerhq/live-common/featureFlags/index";
import getWalletSyncEnvironmentParams from "@ledgerhq/live-common/walletSync/getEnvironmentParams";

export function runWithDevice<T>(
deviceId: string | undefined,
fn: (transport: Transport) => Promise<T>,
): Promise<T> {
return lastValueFrom(withDevice(deviceId || "")(transport => from(fn(transport))));
}

const platformMap: Record<string, string | undefined> = {
darwin: "Mac",
win32: "Windows",
Expand Down Expand Up @@ -52,7 +43,7 @@ export function useTrustchainSdk() {
);

if (sdkInstance === null) {
sdkInstance = getSdk(isMockEnv, defaultContext, lifecycle);
sdkInstance = getSdk(isMockEnv, defaultContext, withDevice, lifecycle);
}

return sdkInstance;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import { getSdk } from "@ledgerhq/trustchain/index";
import { EMPTY } from "rxjs";
import { Flow, initialStateWalletSync, Step } from "~/renderer/reducers/walletSync";
import getWalletSyncEnvironmentParams from "@ledgerhq/live-common/walletSync/getEnvironmentParams";

export const mockedSdk = getSdk(true, {
applicationId: 12,
name: "LLD Integration",
apiBaseUrl: getWalletSyncEnvironmentParams("STAGING").trustchainApiBaseUrl,
});
export const mockedSdk = getSdk(
true,
{
applicationId: 12,
name: "LLD Integration",
apiBaseUrl: getWalletSyncEnvironmentParams("STAGING").trustchainApiBaseUrl,
},
() => () => EMPTY,
);

export const walletSyncActivatedState = {
...initialStateWalletSync,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
import { memberCredentialsSelector, setTrustchain } from "@ledgerhq/trustchain/store";
import { useDispatch, useSelector } from "react-redux";
import { useTrustchainSdk, runWithDevice } from "./useTrustchainSdk";
import {
MemberCredentials,
TrustchainResult,
TrustchainResultType,
} from "@ledgerhq/trustchain/types";
import { useTrustchainSdk } from "./useTrustchainSdk";
import { TrustchainResult, TrustchainResultType } from "@ledgerhq/trustchain/types";
import { useCallback, useEffect, useRef, useState } from "react";
import { Device } from "@ledgerhq/live-common/hw/actions/types";
import { useNavigation } from "@react-navigation/native";
Expand Down Expand Up @@ -40,19 +36,21 @@ export function useAddMember({ device }: { device: Device | null }) {
useEffect(() => {
const addMember = async () => {
try {
await runWithDevice(device?.deviceId || "", async transport => {
const trustchainResult = await sdk.getOrCreateTrustchain(
transport,
memberCredentialsRef.current as MemberCredentials,
{
onStartRequestUserInteraction: () => setUserDeviceInteraction(true),
onEndRequestUserInteraction: () => setUserDeviceInteraction(false),
},
);
if (trustchainResult) {
transitionToNextScreen(trustchainResult);
}
});
if (!device) return;
if (!memberCredentialsRef.current) {
throw new Error("memberCredentials is not set");
}
const trustchainResult = await sdk.getOrCreateTrustchain(
device.deviceId,
memberCredentialsRef.current,
{
onStartRequestUserInteraction: () => setUserDeviceInteraction(true),
onEndRequestUserInteraction: () => setUserDeviceInteraction(false),
},
);
if (trustchainResult) {
transitionToNextScreen(trustchainResult);
}
} catch (error) {
setError(error as Error);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
trustchainSelector,
} from "@ledgerhq/trustchain/store";
import { useDispatch, useSelector } from "react-redux";
import { useTrustchainSdk, runWithDevice } from "./useTrustchainSdk";
import { useTrustchainSdk } from "./useTrustchainSdk";
import { TrustchainMember, Trustchain } from "@ledgerhq/trustchain/types";
import { useCallback, useEffect, useState } from "react";
import { Device } from "@ledgerhq/live-common/hw/actions/types";
Expand Down Expand Up @@ -54,25 +54,23 @@ export function useRemoveMember({ device, member }: Props) {

const removeMember = useCallback(
async (member: TrustchainMember) => {
if (!device) return;
if (!trustchain || !memberCredentials) {
throw new Error("trustchain or memberCredentials is not set");
}
try {
await runWithDevice(device.deviceId, async transport => {
const newTrustchain = await sdk.removeMember(
transport,
trustchain,
memberCredentials,
member,
{
onStartRequestUserInteraction: () => setUserDeviceInteraction(true),
onEndRequestUserInteraction: () => setUserDeviceInteraction(false),
},
);
if (!device) return;
if (!trustchain || !memberCredentials) {
throw new Error("trustchain or memberCredentials is not set");
}
const newTrustchain = await sdk.removeMember(
device.deviceId,
trustchain,
memberCredentials,
member,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

( 👍 on mobile we had cleaner code I hope we can also reach on LLD, see here, no casting )

{
onStartRequestUserInteraction: () => setUserDeviceInteraction(true),
onEndRequestUserInteraction: () => setUserDeviceInteraction(false),
},
);

transitionToNextScreen(newTrustchain);
});
transitionToNextScreen(newTrustchain);
} catch (error) {
if (error instanceof Error) setError(error);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,12 @@
import { firstValueFrom, from } from "rxjs";
import { useMemo } from "react";
import { getEnv } from "@ledgerhq/live-env";
import { getSdk } from "@ledgerhq/trustchain/index";
import Transport from "@ledgerhq/hw-transport";
import { Platform } from "react-native";
import { withDevice } from "@ledgerhq/live-common/hw/deviceAccess";
import { TrustchainSDK } from "@ledgerhq/trustchain/types";
import { useFeature } from "@ledgerhq/live-common/featureFlags/index";
import getWalletSyncEnvironmentParams from "@ledgerhq/live-common/walletSync/getEnvironmentParams";

export function runWithDevice<T>(
deviceId: string,
fn: (transport: Transport) => Promise<T>,
): Promise<T> {
return firstValueFrom(withDevice(deviceId)(transport => from(fn(transport))));
}

const platformMap: Record<string, string | undefined> = {
ios: "iOS",
android: "Android",
Expand All @@ -38,7 +29,7 @@ export function useTrustchainSdk() {
}, [trustchainApiBaseUrl]);

if (sdkInstance === null) {
sdkInstance = getSdk(isMockEnv, defaultContext);
sdkInstance = getSdk(isMockEnv, defaultContext, withDevice);
}

return sdkInstance;
Expand Down
3 changes: 2 additions & 1 deletion apps/web-tools/trustchain/components/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import dynamic from "next/dynamic";
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
import styled from "styled-components";
import { Tooltip } from "react-tooltip";
import { withDevice } from "@ledgerhq/live-common/hw/deviceAccess";
import { MemberCredentials, Trustchain, TrustchainMember } from "@ledgerhq/trustchain/types";
import { getInitialStore } from "@ledgerhq/trustchain/store";
import useEnv from "../useEnv";
Expand Down Expand Up @@ -113,7 +114,7 @@ const App = () => {
);

const sdk = useMemo(
() => getSdk(!!mockEnv, context, lifecycle),
() => getSdk(!!mockEnv, context, withDevice, lifecycle),
// eslint-disable-next-line react-hooks/exhaustive-deps
[
mockEnv,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import {
} from "@ledgerhq/trustchain/types";
import { Actionable } from "./Actionable";
import { useTrustchainSDK } from "../context";
import { runWithDevice } from "../device";

export function AppGetOrCreateTrustchain({
deviceId,
Expand All @@ -26,11 +25,9 @@ export function AppGetOrCreateTrustchain({

const action = useCallback(
(memberCredentials: MemberCredentials) =>
runWithDevice(deviceId, transport =>
sdk
.getOrCreateTrustchain(transport, memberCredentials, callbacks)
.then(result => result.trustchain),
),
sdk
.getOrCreateTrustchain(deviceId, memberCredentials, callbacks)
.then(result => result.trustchain),
[deviceId, sdk, callbacks],
);

Expand Down
15 changes: 7 additions & 8 deletions apps/web-tools/trustchain/components/AppMemberRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {
import { Actionable } from "./Actionable";
import { DisplayName } from "./IdentityManager";
import { useTrustchainSDK } from "../context";
import { runWithDevice } from "../device";

export function AppMemberRow({
deviceId,
Expand All @@ -32,13 +31,13 @@ export function AppMemberRow({

const action = useCallback(
(trustchain: Trustchain, memberCredentials: MemberCredentials) =>
runWithDevice(deviceId, transport =>
sdk.removeMember(transport, trustchain, memberCredentials, member, callbacks),
).then(async trustchain => {
setTrustchain(trustchain);
await sdk.getMembers(trustchain, memberCredentials).then(setMembers);
return member;
}),
sdk
.removeMember(deviceId, trustchain, memberCredentials, member, callbacks)
.then(async trustchain => {
setTrustchain(trustchain);
await sdk.getMembers(trustchain, memberCredentials).then(setMembers);
return member;
}),
[deviceId, sdk, member, setTrustchain, setMembers, callbacks],
);

Expand Down
3 changes: 2 additions & 1 deletion apps/web-tools/trustchain/context.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { useContext } from "react";
import { withDevice } from "@ledgerhq/live-common/hw/deviceAccess";
import { TrustchainSDK } from "@ledgerhq/trustchain/types";
import { getSdk } from "@ledgerhq/trustchain/index";
import { getEnv } from "@ledgerhq/live-env";
Expand All @@ -10,7 +11,7 @@ export const defaultContext = {
};

export const TrustchainSDKContext = React.createContext<TrustchainSDK>(
getSdk(false, defaultContext),
getSdk(false, defaultContext, withDevice),
);

export const useTrustchainSDK = () => useContext(TrustchainSDKContext);
10 changes: 0 additions & 10 deletions apps/web-tools/trustchain/device.ts

This file was deleted.

Loading
Loading