Skip to content
This repository was archived by the owner on Apr 2, 2025. It is now read-only.
Merged

V0.25 #192

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 0 additions & 10 deletions assets/mainWindow/js/loading.js
Original file line number Diff line number Diff line change
Expand Up @@ -299,15 +299,5 @@ function init() {
$('#nativeOnlyBtnCarret').hide();
$('.mode-desc.spv').css('left', '200px');
$('.dropdown-menu.lite').css('left', '180px');
} else {
if (!appConf.experimentalFeatures) {
$('#spvBtn').hide();
$('#spvBtnCarret').hide();
$('.dropdown-menu.native').css('right', '165px');
$('#nativeOnlyBtnCarret').css('margin-right', '0');
$('#settingsBtn').css('margin', '0');
$('.mode-desc.spv').hide();
$('.mode-desc.native').css('left', '180px');
}
}
}
29 changes: 29 additions & 0 deletions react/src/actions/actions/electrum.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});
});
}
2 changes: 1 addition & 1 deletion react/src/components/addcoin/addcoin.js
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ class AddCoin extends React.Component {

updateSelectedCoin(e, index) {
const coin = e.target.value.split('|');
const defaultMode = Config.iguanaLessMode ? 'native' : coin[1];
const defaultMode = coin[1];
const modeToValue = { // TODO: move to utils
'spv': 0,
'native': -1,
Expand Down
2 changes: 1 addition & 1 deletion react/src/components/addcoin/addcoinOptionsAC.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class AddCoinOptionsAC extends React.Component {
let _items = [];

for (let i = 0; i < _assetChains.length; i++) {
let availableModes = _assetChains[i] !== 'kv' && _assetChains[i] !== 'mgw' ? 'native|spv' : 'native';
let availableModes = _assetChains[i] !== 'kv' && _assetChains[i] !== 'mgw' ? 'spv|native' : 'native';

if (mainWindow.arch !== 'x64') {
availableModes = 'spv';
Expand Down
15 changes: 2 additions & 13 deletions react/src/components/addcoin/addcoinOptionsCrypto.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,16 @@ class AddCoinOptionsCrypto extends React.Component {
constructor() {
super();
this.state = {
isExperimentalOn: false,
};
}

componentWillMount() {
const appConfig = mainWindow.appConfig;

this.setState({
isExperimentalOn: appConfig.experimentalFeatures,
});
}

render() {
let availableKMDModes = mainWindow.arch === 'x64' ? 'native|spv' : 'spv';
let availableKMDModes = mainWindow.arch === 'x64' ? 'spv|native' : 'spv';

return (
<optgroup label={ translate('ADD_COIN.CRYPTO_CURRENCIES') }>
<option value={ `KMD|${availableKMDModes}` }>Komodo (KMD)</option>
<option
value="CHIPS|spv"
className={ this.state.isExperimentalOn ? '' : 'hide' }>Chips (CHIPS)</option>
<option value="CHIPS|spv">Chips (CHIPS)</option>
</optgroup>
);
}
Expand Down
2 changes: 1 addition & 1 deletion react/src/components/addcoin/coin-selectors.render.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ const CoinSelectorsRender = function(item, coin, i) {
</button>
</div>
<div className="col-sm-11 text-center add-coin-modes">
<div className={ this.state.isExperimentalOn ? 'form-group col-lg-4 col-md-4 col-sm-6 col-xs-6 style-addcoin-lbl-mdl-login' : 'hide' }>
<div className="form-group col-lg-4 col-md-4 col-sm-6 col-xs-6 style-addcoin-lbl-mdl-login">
<input
type="radio"
className="to-labelauty labelauty"
Expand Down
182 changes: 182 additions & 0 deletions react/src/components/dashboard/settings/settings.bip39KeysPanel.js
Original file line number Diff line number Diff line change
@@ -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 changes: 6 additions & 0 deletions react/src/components/dashboard/settings/settings.render.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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' }
Expand Down
3 changes: 3 additions & 0 deletions react/src/translate/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -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.',
Expand Down