-
Notifications
You must be signed in to change notification settings - Fork 12
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
WIP: Add signers #32
WIP: Add signers #32
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some notes
pinEntryDevice: null, | ||
} | ||
|
||
toggle() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method and state.modal
needs to be renamed to like toggleDeviceInstructionsModal
or something.
Originally I just had 1 modal and the generic names haven't been updated yet ...
@@ -14,6 +14,15 @@ | |||
logger = logging.getLogger(__name__) | |||
CLIENT = None | |||
|
|||
def kill_client(): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The same instance of trezor.TrezorClient()
must prompt and send the pin. Therefore, we implement it as a global variable. But we need to close it when we're done using or we get "device is busy" errors when creating competing instances. Therefore, I close it wherever possible.
# FIXME: or path??? | ||
'fingerprint': { 'type': 'string' }, # FIXME: regex | ||
# device_id is fingerprint or path | ||
'device_id': { 'type': 'string' }, # FIXME: regex |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@wbobeirne went with your idea here to accept fingerprint
or path
|
||
class AddDevice extends React.Component<AddDeviceProps> { | ||
handleUnlock(device: Device) { | ||
api.promptPin({ path: device.path }).then(this.props.displayPinEntry) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The modal is weird. We want to have HWI prompt pin every time the modal is displayed, but because the modal component is always rendered and just pops in and out of view, we can't prompt pin entry on componentWillMount
or something like that ...
I'm sure there's a better way than this ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Two ways to go about this. One is to make a sub-component that only renders when the modal is open, and use that component's componentDidMount
. Alternatively, you can use componentDidUpdate
like so:
componentDidUpdate(prevProps: Props) {
if (this.props.isOpen && !prevProps.isOpen) {
// Do thing on modal open
}
}
modal: boolean; | ||
pinModalActive: boolean; | ||
// FIXME: keeping track of the device outside the modal sucks | ||
pinEntryDevice: Device | null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This sucks. Since the modal is rendered before a user chooses which device to unlock, we have to keep track of the chosen device in the parent component and pass to the pin entry component. But it works.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems pretty reasonable to me, IMO. However, maybe the "cooler" option would be to have a global component rendered way further up in the stack, and to trigger pin entries via redux. There could be a state prop called pinDevice
or something like that, and you just call this.props.promptPin(device)
, it sets it in redux state, and causes that modal to render and take it from there.
})); | ||
} | ||
|
||
openModal(device: Device) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Janky code to communicate the device to modal
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could just consolidate the two props into one be informing modal openness from whether or not you have a pin entry device set, i.e. isOpen={!!this.state.pinEntryDevice}
isOpen: boolean; | ||
} | ||
|
||
export default class DeviceInstructionsModal extends React.Component<Props> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Someone is a VSCode noob who haven't figured out how to do indentation properly ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can get prettier setup on this sucker to avoid code style issues 💪
src/components/EnterPinModal.tsx
Outdated
} | ||
|
||
handleMouseDown(digit: number) { | ||
if (!this.state.submitting) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this a good way to dispable buttons when they shouldn't be clicked?
Or should I use a disabled=bool
HTML attribute?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
disabled works pretty nicely on Reactstrap buttons, so I'd go with that. But doing it in both places doesn't hurt either.
// This is hard to use | ||
export function selectActiveWallet(state: AppState) { | ||
const { activeWallet } = state.wallet; | ||
// if (activeWallet === null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried this selector that throws if there is no active wallet. I found it hard to use. React is always trying to render ... this approach needs some way to tell react not to render until wallets are loaded. Also, some way to redirect user through onboarding steps (#1 update settings, #2 create wallet) if wallets are loaded and no active wallet exists.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, you'd want a wrapper or higher order component for that, sorry for the my earlier red herring solution (Which does work in some cases, just not the one here.) Something like:
<RequireWallet component={MyComponent} />
where RequireWallet
's render looks like
if (this.props.activeWallet) {
return <MyComponent activeWallet={this.props.activeWallet} />
} else {
return 'Oh no you need a wallet fam';
}
} | ||
|
||
// FIXME: some of these are null at times | ||
// but I don't really want typescript yelling at me all the time ... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is weird. I should be saying that some of these properties can be be null. But then typescript relentlessly yells at me in places where I know the properties will exist.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We'd need union types for those. What are the cases where you know it will be null, and know it won't?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Haven't run yet, but here are some notes!
|
||
class AddDevice extends React.Component<AddDeviceProps> { | ||
handleUnlock(device: Device) { | ||
api.promptPin({ path: device.path }).then(this.props.displayPinEntry) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Two ways to go about this. One is to make a sub-component that only renders when the modal is open, and use that component's componentDidMount
. Alternatively, you can use componentDidUpdate
like so:
componentDidUpdate(prevProps: Props) {
if (this.props.isOpen && !prevProps.isOpen) {
// Do thing on modal open
}
}
|
||
deletePrompt() { | ||
return this.request<any>('DELETE', '/prompt',) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should type all of these responses at some point, <any>
was only meant as a placeholder.
rightComponent = <Button onClick={() => this.handleUnlock(device)}>Unlock</Button> | ||
// TODO | ||
// } else if (device.needs_pin_sent) { | ||
// rightComponent = <Button onClick={enterPassphrase}>Unlock</Button> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this conditional right? Or is it mean for needs_password_somethingorother
?
modal: boolean; | ||
pinModalActive: boolean; | ||
// FIXME: keeping track of the device outside the modal sucks | ||
pinEntryDevice: Device | null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems pretty reasonable to me, IMO. However, maybe the "cooler" option would be to have a global component rendered way further up in the stack, and to trigger pin entries via redux. There could be a state prop called pinDevice
or something like that, and you just call this.props.promptPin(device)
, it sets it in redux state, and causes that modal to render and take it from there.
})); | ||
} | ||
|
||
openModal(device: Device) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could just consolidate the two props into one be informing modal openness from whether or not you have a pin entry device set, i.e. isOpen={!!this.state.pinEntryDevice}
{activeWallet.balances.unconfirmed > 0 && | ||
<div>Unconfirmed Balance: {activeWallet.balances.unconfirmed}</div>} | ||
{signersComponent} | ||
{addSigners} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be good to stick with one style of conditional rendering for consistency's sake. Here both variable assignment in conditional, and in-jsx checking is done. addSigners
and signersComponent
could both be done with in-jsx conditionals.
import { Signer, Device } from '../../types' | ||
|
||
export function selectCandidateDevicesForActiveWallet(state: AppState) { | ||
// FIXME this check sucks |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems reasonable to me 🤷♂
src/store/wallet/selectors.ts
Outdated
candidates.push(device); | ||
} | ||
return candidates; | ||
}, []) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
filter
is probably a better method than reduce for this.
// This is hard to use | ||
export function selectActiveWallet(state: AppState) { | ||
const { activeWallet } = state.wallet; | ||
// if (activeWallet === null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, you'd want a wrapper or higher order component for that, sorry for the my earlier red herring solution (Which does work in some cases, just not the one here.) Something like:
<RequireWallet component={MyComponent} />
where RequireWallet
's render looks like
if (this.props.activeWallet) {
return <MyComponent activeWallet={this.props.activeWallet} />
} else {
return 'Oh no you need a wallet fam';
}
} | ||
|
||
// FIXME: some of these are null at times | ||
// but I don't really want typescript yelling at me all the time ... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We'd need union types for those. What are the cases where you know it will be null, and know it won't?
…ed components with RequireData wrapper component.
One big problem:
activeWallet
goes stale after updates to the wallet list. Perhaps it would be better to just keep track of theactiveWalletName
and have a selector that uses it to looks upactiveWallet
...