You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

389 lines
10 KiB

import React from 'react';
import {
toggleAddcoinModal,
iguanaWalletPassphrase,
iguanaActiveHandle,
startInterval,
getDexCoins,
toggleSyncOnlyModal,
getSyncOnlyForks,
createNewWallet,
triggerToaster,
toggleLoginSettingsModal
} from '../../actions/actionCreators';
import Config from '../../config';
import Store from '../../store';
import { PassPhraseGenerator } from '../../util/crypto/passphrasegenerator';
import SwallModalRender from './swall-modal.render';
import LoginRender from './login.render';
import { translate } from '../../translate/translate';
const IGUNA_ACTIVE_HANDLE_TIMEOUT = 3000;
const IGUNA_ACTIVE_COINS_TIMEOUT = 10000;
// TODO: remove duplicate activehandle and activecoins calls
class Login extends React.Component {
constructor(props) {
super(props);
this.state = {
display: false,
activeLoginSection: 'activateCoin',
loginPassphrase: '',
seedInputVisibility: false,
loginPassPhraseSeedType: null,
bitsOption: 256,
randomSeed: PassPhraseGenerator.generatePassPhrase(256),
randomSeedConfirm: '',
isSeedConfirmError: false,
isSeedBlank: false,
displaySeedBackupModal: false,
customWalletSeed: false,
isCustomSeedWeak: false,
nativeOnly: Config.iguanaLessMode,
trimPassphraseTimer: null,
displayLoginSettingsDropdown: false,
displayLoginSettingsDropdownSection: null,
};
this.toggleActivateCoinForm = this.toggleActivateCoinForm.bind(this);
this.updateRegisterConfirmPassPhraseInput = this.updateRegisterConfirmPassPhraseInput.bind(this);
this.updateLoginPassPhraseInput = this.updateLoginPassPhraseInput.bind(this);
this.loginSeed = this.loginSeed.bind(this);
this.toggleSeedInputVisibility = this.toggleSeedInputVisibility.bind(this);
this.handleRegisterWallet = this.handleRegisterWallet.bind(this);
this.openSyncOnlyModal = this.openSyncOnlyModal.bind(this);
this.toggleSeedBackupModal = this.toggleSeedBackupModal.bind(this);
this.copyPassPhraseToClipboard = this.copyPassPhraseToClipboard.bind(this);
this.execWalletCreate = this.execWalletCreate.bind(this);
this.resizeLoginTextarea = this.resizeLoginTextarea.bind(this);
this.toggleLoginSettingsDropdown = this.toggleLoginSettingsDropdown.bind(this);
}
// the setInterval handler for 'activeCoins'
_iguanaActiveCoins = null;
toggleLoginSettingsDropdownSection(sectionName) {
Store.dispatch(toggleLoginSettingsModal(true));
this.setState({
displayLoginSettingsDropdown: false,
displayLoginSettingsDropdownSection: sectionName,
});
}
isCustomWalletSeed() {
return this.state.customWalletSeed;
}
toggleCustomWalletSeed() {
this.setState({
customWalletSeed: !this.state.customWalletSeed
}, () => {
// if customWalletSeed is set to false, regenerate the seed
if (!this.state.customWalletSeed) {
this.setState({
randomSeed: PassPhraseGenerator.generatePassPhrase(this.state.bitsOption),
isSeedConfirmError: false,
isSeedBlank: false,
});
} else {
// if customWalletSeed is set to true, reset to seed to an empty string
this.setState({
randomSeed: '',
randomSeedConfirm: '',
});
}
});
}
openSyncOnlyModal() {
Store.dispatch(getSyncOnlyForks());
const _iguanaActiveHandle = setInterval(() => {
Store.dispatch(getSyncOnlyForks());
}, IGUNA_ACTIVE_HANDLE_TIMEOUT);
Store.dispatch(
startInterval(
'syncOnly',
_iguanaActiveHandle
)
);
Store.dispatch(toggleSyncOnlyModal(true));
this.setState({
displayLoginSettingsDropdown: false,
});
}
componentDidMount() {
Store.dispatch(iguanaActiveHandle(true));
}
toggleSeedInputVisibility() {
this.setState({
seedInputVisibility: !this.state.seedInputVisibility,
});
this.resizeLoginTextarea();
}
generateNewSeed(bits) {
this.setState(Object.assign({}, this.state, {
randomSeed: PassPhraseGenerator.generatePassPhrase(bits),
bitsOption: bits,
isSeedBlank: false,
}));
}
toggleLoginSettingsDropdown() {
this.setState(Object.assign({}, this.state, {
displayLoginSettingsDropdown: !this.state.displayLoginSettingsDropdown,
}));
}
componentWillReceiveProps(props) {
if (props &&
props.Main &&
props.Main.isLoggedIn) {
this.setState({
display: false,
});
}
if (props &&
props.Main &&
!props.Main.isLoggedIn) {
this.setState({
display: true,
});
if (!this.props.Interval.interval.activeCoins) {
// only start a new 'activeCoins' interval if a previous one doesn't exist
if (!this._iguanaActiveCoins) {
this._iguanaActiveCoins = setInterval(() => {
Store.dispatch(getDexCoins());
}, IGUNA_ACTIVE_COINS_TIMEOUT);
Store.dispatch(startInterval('activeCoins', this._iguanaActiveCoins));
}
}
document.body.className = 'page-login layout-full page-dark';
}
if (this.state.activeLoginSection !== 'signup') {
if (props &&
props.Main &&
props.Main.activeCoins) {
this.setState({
activeLoginSection: 'login',
});
} else {
this.setState({
activeLoginSection: 'activateCoin',
});
}
}
}
toggleActivateCoinForm() {
Store.dispatch(toggleAddcoinModal(true, false));
}
resizeLoginTextarea() {
// auto-size textarea
setTimeout(() => {
if (this.state.seedInputVisibility) {
document.querySelector('#loginPassphrase').style.height = '1px';
document.querySelector('#loginPassphrase').style.height = `${(15 + document.querySelector('#loginPassphrase').scrollHeight)}px`;
}
}, 100);
}
updateLoginPassPhraseInput(e) {
// 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({
loginPassphrase: newValue ? newValue.trim() : '', // hardcoded field name
loginPassPhraseSeedType: this.getLoginPassPhraseSeedType(newValue),
});
}, 2000);
this.resizeLoginTextarea();
this.setState({
trimPassphraseTimer: _trimPassphraseTimer,
[e.target.name]: newValue,
loginPassPhraseSeedType: this.getLoginPassPhraseSeedType(newValue),
});
}
updateRegisterConfirmPassPhraseInput(e) {
this.setState({
[e.target.name]: e.target.value,
isSeedConfirmError: false,
isSeedBlank: this.isBlank(e.target.value),
});
}
updateWalletSeed(e) {
this.setState({
randomSeed: e.target.value,
isSeedConfirmError: false,
isSeedBlank: this.isBlank(e.target.value),
});
}
loginSeed() {
// reset the login pass phrase values so that when the user logs out, the values are clear
this.setState({
loginPassphrase: null,
loginPassPhraseSeedType: null,
});
Store.dispatch(
iguanaWalletPassphrase(this.state.loginPassphrase)
);
}
getLoginPassPhraseSeedType(passPhrase) {
if (!passPhrase) {
return null;
}
const passPhraseWords = passPhrase.split(' ');
if (!PassPhraseGenerator.arePassPhraseWordsValid(passPhraseWords)) {
return null;
}
if (PassPhraseGenerator.isPassPhraseValid(passPhraseWords, 256)) {
return translate('LOGIN.IGUANA_SEED');
}
if (PassPhraseGenerator.isPassPhraseValid(passPhraseWords, 160)) {
return translate('LOGIN.WAVES_SEED');
}
if (PassPhraseGenerator.isPassPhraseValid(passPhraseWords, 128)) {
return translate('LOGIN.NXT_SEED');
}
return null;
}
updateActiveLoginSection(name) {
// reset login/create form
this.setState({
activeLoginSection: name,
loginPassphrase: null,
loginPassPhraseSeedType: null,
seedInputVisibility: false,
bitsOption: 256,
randomSeed: PassPhraseGenerator.generatePassPhrase(256),
randomSeedConfirm: '',
isSeedConfirmError: false,
isSeedBlank: false,
displaySeedBackupModal: false,
customWalletSeed: false,
isCustomSeedWeak: false,
});
}
execWalletCreate() {
Store.dispatch(
createNewWallet(
this.state.randomSeedConfirm,
this.props.Dashboard.activeHandle
)
);
this.setState({
activeLoginSection: 'activateCoin',
displaySeedBackupModal: false,
isSeedConfirmError: false,
});
}
// TODO: disable register btn if seed or seed conf is incorrect
handleRegisterWallet() {
const enteredSeedsMatch = this.state.randomSeed === this.state.randomSeedConfirm;
const isSeedBlank = this.isBlank(this.state.randomSeed);
// if custom seed check for string strength
// at least 1 letter in upper case
// at least 1 digit
// at least one special char
// min length 10 chars
const _customSeed = this.state.customWalletSeed ? this.state.randomSeed.match('^(?=.*[A-Z])(?=.*[^<>{}\"/|;:.,~!?@#$%^=&*\\]\\\\()\\[_+]*$)(?=.*[0-9])(?=.*[a-z]).{10,99}$') : false;
this.setState({
isCustomSeedWeak: _customSeed === null ? true : false,
isSeedConfirmError: !enteredSeedsMatch ? true : false,
isSeedBlank: isSeedBlank ? true : false,
});
if (enteredSeedsMatch && !isSeedBlank && _customSeed !== null) {
this.toggleSeedBackupModal();
}
}
isBlank(str) {
return (!str || /^\s*$/.test(str));
}
handleKeydown(e) {
this.updateLoginPassPhraseInput(e);
if (e.key === 'Enter') {
this.loginSeed();
}
}
toggleSeedBackupModal() {
this.setState(Object.assign({}, this.state, {
displaySeedBackupModal: !this.state.displaySeedBackupModal,
}));
}
copyPassPhraseToClipboard() {
const passPhrase = this.state.randomSeed;
const textField = document.createElement('textarea');
textField.innerText = passPhrase;
document.body.appendChild(textField);
textField.select();
document.execCommand('copy');
textField.remove();
Store.dispatch(
triggerToaster(
translate('LOGIN.SEED_SUCCESSFULLY_COPIED'),
translate('LOGIN.SEED_COPIED'),
'success'
)
);
}
renderSwallModal() {
if (this.state.displaySeedBackupModal) {
return SwallModalRender.call(this);
}
return null;
}
render() {
if ((this.state && this.state.display) ||
!this.props.Main) {
return LoginRender.call(this);
}
return null;
}
}
export default Login;