Browse Source

settings bip39 key search panel

v0.25
pbca26 7 years ago
parent
commit
cf0003e090
  1. 29
      react/src/actions/actions/electrum.js
  2. 182
      react/src/components/dashboard/settings/settings.bip39KeysPanel.js
  3. 6
      react/src/components/dashboard/settings/settings.render.js
  4. 3
      react/src/translate/en.js

29
react/src/actions/actions/electrum.js

@ -311,4 +311,33 @@ export function shepherdElectrumListunspent(coin, address) {
}
});
});
}
export function shepherdElectrumBip39Keys(seed, match) {
return new Promise((resolve, reject) => {
fetch(`http://127.0.0.1:${Config.agamaPort}/shepherd/electrum/seed/bip39/match`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
seed,
match,
}),
})
.catch((error) => {
console.log(error);
Store.dispatch(
triggerToaster(
'shepherdElectrumSetServer',
'Error',
'error'
)
);
})
.then(response => response.json())
.then(json => {
resolve(json);
});
});
}

182
react/src/components/dashboard/settings/settings.bip39KeysPanel.js

@ -0,0 +1,182 @@
import React from 'react';
import { translate } from '../../../translate/translate';
import { connect } from 'react-redux';
import {
shepherdElectrumBip39Keys,
copyCoinAddress,
triggerToaster,
} from '../../../actions/actionCreators';
import Store from '../../../store';
class Bip39KeysPanel extends React.Component {
constructor() {
super();
this.state = {
keys: null,
match: '',
passphrase: '',
seedInputVisibility: false,
trimPassphraseTimer: null,
};
this._getBip39Keys = this._getBip39Keys.bind(this);
this.updateInput = this.updateInput.bind(this);
this.toggleSeedInputVisibility = this.toggleSeedInputVisibility.bind(this);
this._copyCoinAddress = this._copyCoinAddress.bind(this);
}
componentWillReceiveProps(props) {
if (props.Dashboard &&
props.Dashboard.activeSection !== 'settings') {
// reset input vals
this.refs.passphrase.value = '';
this.refs.passphraseTextarea.value = '';
this.setState(Object.assign({}, this.state, {
passphrase: '',
keys: null,
match: null,
}));
}
}
toggleSeedInputVisibility() {
this.setState({
seedInputVisibility: !this.state.seedInputVisibility,
});
}
updateInput(e) {
if (e.target.name === 'passphrase') {
// remove any empty chars from the start/end of the string
const newValue = e.target.value;
clearTimeout(this.state.trimPassphraseTimer);
const _trimPassphraseTimer = setTimeout(() => {
this.setState({
passphrase: newValue ? newValue.trim() : '', // hardcoded field name
});
}, 2000);
this.resizeLoginTextarea();
this.setState({
trimPassphraseTimer: _trimPassphraseTimer,
[e.target.name === 'passphraseTextarea' ? 'passphrase' : e.target.name]: newValue,
});
} else {
this.setState({
[e.target.name === 'passphraseTextarea' ? 'passphrase' : e.target.name]: e.target.value,
});
}
}
resizeLoginTextarea() {
// auto-size textarea
setTimeout(() => {
if (this.state.seedInputVisibility) {
document.querySelector('#passphraseTextarea').style.height = '1px';
document.querySelector('#passphraseTextarea').style.height = `${(15 + document.querySelector('#passphraseTextarea').scrollHeight)}px`;
}
}, 100);
}
_copyCoinAddress(address) {
Store.dispatch(copyCoinAddress(address));
}
_getBip39Keys() {
shepherdElectrumBip39Keys(this.state.passphrase, this.state.match)
.then((res) => {
this.setState({
keys: res.result.priv ? res.result : 'empty',
});
});
}
updateInput(e) {
this.setState({
[e.target.name]: e.target.value,
});
}
render() {
return (
<div>
<div className="row">
<div className="col-sm-12 padding-bottom-10">
<h4 className="col-red">
<i className="fa fa-warning"></i> { translate('SETTINGS.BIP39_DISC') }
</h4>
<div>{ translate('SETTINGS.BIP39_DESC_P1') }</div>
<div>{ translate('SETTINGS.BIP39_DESC_P2') }</div>
<div>
<div className="col-sm-12 no-padding-left margin-top-10">
<div className="form-group form-material floating">
<input
type="password"
className={ !this.state.seedInputVisibility ? 'form-control' : 'hide' }
autoComplete="off"
name="passphrase"
ref="passphrase"
id="passphrase"
onChange={ this.updateInput }
value={ this.state.passphrase } />
<textarea
className={ this.state.seedInputVisibility ? 'form-control' : 'hide' }
autoComplete="off"
id="passphraseTextarea"
ref="passphraseTextarea"
name="passphraseTextarea"
onChange={ this.updateInput }
value={ this.state.passphrase }></textarea>
<i
className={ 'seed-toggle fa fa-eye' + (!this.state.seedInputVisibility ? '-slash' : '') }
onClick={ this.toggleSeedInputVisibility }></i>
<label
className="floating-label"
htmlFor="passphrase">{ translate('INDEX.PASSPHRASE') }</label>
</div>
</div>
<div className="col-sm-4 no-padding-left text-center">
<input
type="text"
className="form-control margin-top-10"
autoComplete="off"
name="match"
onChange={ this.updateInput }
placeholder="Search key pattern"
value={ this.state.match } />
<button
type="button"
className="btn btn-primary waves-effect waves-light margin-top-20"
disabled={ !this.state.match || !this.state.passphrase || this.state.passphrase.length < 2 }
onClick={ this._getBip39Keys }>Get key</button>
</div>
</div>
</div>
{ this.state.keys &&
<div className="col-sm-12 margin-top-30 margin-bottom-20">
{ this.state.keys !== 'empty' &&
<div>
<strong>WIF:</strong> <span>{ this.state.keys.priv }</span>
<button
className="btn btn-default btn-xs clipboard-edexaddr margin-left-10"
title={ translate('INDEX.COPY_TO_CLIPBOARD') }
onClick={ () => this._copyCoinAddress(this.state.keys.priv) }>
<i className="icon wb-copy"></i> { translate('INDEX.COPY') }
</button>
</div>
}
{ this.state.keys === 'empty' &&
<strong>Key is not found</strong>
}
</div>
}
</div>
</div>
);
};
}
export default Bip39KeysPanel;

6
react/src/components/dashboard/settings/settings.render.js

@ -17,6 +17,7 @@ import SPVServersPanel from './settings.spvServersPanel';
import DaemonStdoutPanel from './settings.daemonStdoutPanel';
import NativeWalletDatKeysPanel from './settings.nativeWalletDatKeysPanel';
import CoindClearDataDirPanel from './settings.coindClearDataDirPanel';
import Bip39KeysPanel from './settings.bip39KeysPanel';
import mainWindow from '../../../util/mainWindow';
// import WalletInfoPanel from './settings.walletInfoPanel';
@ -118,6 +119,11 @@ export const SettingsRender = function() {
<NativeWalletDatKeysPanel />
</PanelSection>
}
<PanelSection
title="BIP39 Keys"
icon="icon fa-usb">
<Bip39KeysPanel />
</PanelSection>
{ mainWindow.arch === 'x64' &&
<PanelSection
title={ 'Clear native coin data dir' }

3
react/src/translate/en.js

@ -604,6 +604,9 @@ export const _lang = {
'JUMBLR_MOTTO': 'Secure, Native and Decentralised Coin Anonymizer',
},
'SETTINGS': {
'BIP39_DISC': 'Hardware wallets disclaimer: by using this form you\'re acknowledging risks of exposing your seed',
'BIP39_DESC_P1': 'Description: the form below is going to search for a pub key in a range of 20 accounts with 50 addresses depth each (1000 keys).',
'BIP39_DESC_P2': 'The app might temporary freeze for several seconds during search procedure.',
'SHOW_APP_RUNTIME_LOG': 'Show app runtime log',
'WRONG_PASSPHRASE': 'Wrong passphrase!',
'SPV_SERVER_LIST_DESC': 'Server list selection is only available for active coins that have more than 1 server to connect to.',

Loading…
Cancel
Save