Skip to content

Commit

Permalink
feat: rebuild transport
Browse files Browse the repository at this point in the history
  • Loading branch information
kyranjamie committed Jan 14, 2021
1 parent 2d4c063 commit 850aa75
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 95 deletions.
162 changes: 83 additions & 79 deletions app/hooks/use-ledger.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import { useRef, useEffect, useCallback, useState } from 'react';
import BlockstackApp, { LedgerError } from '@zondax/ledger-blockstack';
import type Transport from '@ledgerhq/hw-transport';
import TransportNodeHid from '@ledgerhq/hw-transport-node-hid';

import { useInterval } from './use-interval';
import { safeAwait } from '@utils/safe-await';
import { useInterval } from '@hooks/use-interval';

export enum LedgerConnectStep {
Disconnected,
Expand All @@ -14,80 +12,86 @@ export enum LedgerConnectStep {
}

export function useLedger() {
// const [step, setStep] = useState(LedgerConnectStep.Disconnected);
// const [usbError, setUsbError] = useState<string | null>(null);
// const transport = useRef<Transport | null>(null);
// const disconnectTimeouts = useRef<number>(0);
// const listeningForAddEvent = useRef(true);
// const SAFE_ASSUME_REAL_DEVICE_DISCONNECT_TIME = 1000;
// const POLL_LEDGER_INTERVAL = 250;
// const createListener = useCallback(() => {
// const tHid = TransportNodeHid.listen({
// next: async event => {
// if (event.type === 'add') {
// clearTimeout(disconnectTimeouts.current);
// tHid.unsubscribe();
// const [error, t] = await safeAwait(TransportNodeHid.open(event.descriptor));
// if (error) {
// console.log(error);
// setUsbError('Unable to connect to device. You may need to configure your udev rules.');
// return;
// }
// if (t) {
// setUsbError(null);
// t.on('disconnect', async () => {
// listeningForAddEvent.current = true;
// transport.current = null;
// await t.close();
// const timer = setTimeout(() => {
// setStep(LedgerConnectStep.Disconnected);
// }, SAFE_ASSUME_REAL_DEVICE_DISCONNECT_TIME);
// disconnectTimeouts.current = (timer as unknown) as number;
// createListener();
// });
// listeningForAddEvent.current = false;
// transport.current = t;
// }
// }
// },
// error: () => ({}),
// complete: () => ({}),
// });
// return tHid;
// }, []);
// useEffect(() => {
// const subscription = createListener();
// return () => {
// subscription.unsubscribe();
// if (transport.current) {
// void transport.current.close();
// transport.current = null;
// }
// };
// }, [createListener]);
// useInterval(() => {
// if (
// transport.current &&
// step !== LedgerConnectStep.HasAddress &&
// !listeningForAddEvent.current
// ) {
// // There's a bug with the node-hid library where it doesn't
// // fire disconnect event until next time an operation using it is called.
// // Here we poll a request to ensure the event is fired
// void new BlockstackApp(transport.current)
// .getVersion()
// .then(resp => {
// if (resp.returnCode === LedgerError.AppDoesNotSeemToBeOpen)
// return setStep(LedgerConnectStep.ConnectedAppClosed);
// if (resp.returnCode === LedgerError.NoErrors)
// return setStep(LedgerConnectStep.ConnectedAppOpen);
// })
// .catch(() => ({}));
// }
// }, POLL_LEDGER_INTERVAL);
// return {
// transport: transport.current,
// step,
// error: usbError,
// };
const [step, setStep] = useState(LedgerConnectStep.Disconnected);
const [usbError, setUsbError] = useState<string | null>(null);
const transport = useRef<Transport | null>(null);
const disconnectTimeouts = useRef<number>(0);
const listeningForAddEvent = useRef(true);
const closeTransport = useRef(() => {});
const SAFE_ASSUME_REAL_DEVICE_DISCONNECT_TIME = 1000;
const POLL_LEDGER_INTERVAL = 250;
const createListener = useCallback(() => {
const tHid = api.nodeHid.listen({
next: async (event: any) => {
if (event.type === 'add') {
clearTimeout(disconnectTimeouts.current);
tHid.unsubscribe();
const [error, resp] = await safeAwait(
api.nodeHid.open({
descriptor: event.descriptor,
onDisconnect: () => {
listeningForAddEvent.current = true;
transport.current = null;
const timer = setTimeout(() => {
setStep(LedgerConnectStep.Disconnected);
}, SAFE_ASSUME_REAL_DEVICE_DISCONNECT_TIME);
disconnectTimeouts.current = (timer as unknown) as number;
createListener();
},
})
);
if (error) {
console.log(error);
setUsbError('Unable to connect to device. You may need to configure your udev rules.');
return;
}
if (resp) {
closeTransport.current = resp.closeTransportConnection;
console.log(transport);
setUsbError(null);
listeningForAddEvent.current = false;
transport.current = resp.transport;
}
}
},
error: () => ({}),
complete: () => ({}),
});
return tHid;
}, []);
useEffect(() => {
const subscription = createListener();
return () => {
subscription.unsubscribe();
if (closeTransport.current) {
void closeTransport.current();
transport.current = null;
}
};
}, [createListener]);
useInterval(() => {
if (
transport.current &&
step !== LedgerConnectStep.HasAddress &&
!listeningForAddEvent.current
) {
// There's a bug with the node-hid library where it doesn't
// fire disconnect event until next time an operation using it is called.
// Here we poll a request to ensure the event is fired
void new BlockstackApp(transport.current)
.getVersion()
.then(resp => {
if (resp.returnCode === LedgerError.AppDoesNotSeemToBeOpen)
return setStep(LedgerConnectStep.ConnectedAppClosed);
if (resp.returnCode === LedgerError.NoErrors)
return setStep(LedgerConnectStep.ConnectedAppOpen);
})
.catch(() => ({}));
}
}, POLL_LEDGER_INTERVAL);
return {
transport: transport.current,
step,
error: usbError,
};
}
4 changes: 3 additions & 1 deletion app/main.dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ import contextMenu from 'electron-context-menu';
import MenuBuilder from './menu';
import { deriveKey } from './crypto/key-generation';
import Store from 'electron-store';
// import fs from 'fs';
import TransportNodeHid from '@ledgerhq/hw-transport-node-hid';
import { safeAwait } from './utils/safe-await';
import BlockstackApp, { LedgerError } from '@zondax/ledger-blockstack';

// CSP enabled in production mode, don't warn in development
delete process.env.ELECTRON_ENABLE_SECURITY_WARNINGS;
Expand Down
23 changes: 20 additions & 3 deletions app/preload.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
/* eslint-disable @typescript-eslint/no-var-requires */
console.log('preload');

const fs = require('fs');
const { contextBridge, ipcRenderer, app } = require('electron');
const Store = require('electron-store');
const fs = require('fs');

const TransportNodeHid = require('@ledgerhq/hw-transport-node-hid').default;

const scriptsToLoad = [];

Expand Down Expand Up @@ -47,4 +47,21 @@ contextBridge.exposeInMainWorld('api', {
console.log('deriveKey', args);
return ipcRenderer.invoke('derive-key', args);
},

nodeHid: {
listen: observer => TransportNodeHid.listen(observer),
open: async ({ descriptor, onDisconnect }) => {
const transport = await TransportNodeHid.open(descriptor);
transport.on('disconnect', async () => {
await transport.close();
onDisconnect();
});
return {
transport,
closeTransportConnection: async () => {
await transport.close();
},
};
},
},
});
11 changes: 11 additions & 0 deletions app/types/file-types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
declare module '*.svg' {
const content: any;
// eslint-disable-next-line import/no-default-export
export default content;
}

declare module '*.woff2' {
const content: any;
// eslint-disable-next-line import/no-default-export
export default content;
}
23 changes: 11 additions & 12 deletions app/types/index.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,3 @@
declare module '*.svg' {
const content: any;
// eslint-disable-next-line import/no-default-export
export default content;
}

declare module '*.woff2' {
const content: any;
// eslint-disable-next-line import/no-default-export
export default content;
}

declare const api: {
deriveKey: ({
pass,
Expand All @@ -26,4 +14,15 @@ declare const api: {
getEntireStore(): any;
initialValue: Record<string, unknown>;
};

nodeHid: {
listen: typeof import('@ledgerhq/hw-transport').default['listen'];
open({
descriptor,
onDisconnect,
}: {
descriptor: string;
onDisconnect(): void;
}): Promise<{ transport: any; closeTransportConnection(): Promise<void> }>;
};
};

0 comments on commit 850aa75

Please sign in to comment.