diff --git a/react/src/actions/actionCreators.js b/react/src/actions/actionCreators.js index 20865413d..f6e862982 100644 --- a/react/src/actions/actionCreators.js +++ b/react/src/actions/actionCreators.js @@ -29,6 +29,7 @@ import { DISPLAY_CLAIM_INTEREST_MODAL, START_INTERVAL, STOP_INTERVAL, + GET_PIN_LIST, DASHBOARD_SYNC_ONLY_UPDATE, DISPLAY_IMPORT_KEY_MODAL, } from './storeType'; @@ -345,6 +346,13 @@ export function toggleClaimInterestModal(display) { } } +export function getPinList(pinList) { + return { + type: GET_PIN_LIST, + pinList: pinList, + } +} + export function skipFullDashboardUpdate(skip) { return { type: DASHBOARD_SYNC_ONLY_UPDATE, diff --git a/react/src/actions/actions/pin.js b/react/src/actions/actions/pin.js new file mode 100644 index 000000000..58d600e77 --- /dev/null +++ b/react/src/actions/actions/pin.js @@ -0,0 +1,106 @@ +import Config from '../../config'; +import { getDecryptedPassphrase, getPinList, triggerToaster } from "../actionCreators"; +import { iguanaWalletPassphrase } from "./walletAuth"; + +export function encryptPassphrase(passphrase, key, pubKey) { + const payload = { + string: passphrase, + key: key, + pubkey: pubKey, + }; + + return dispatch => { + return fetch(`http://127.0.0.1:${Config.agamaPort}/shepherd/encryptkey`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(payload), + }) + .catch(function(error) { + console.log(error); + dispatch( + triggerToaster( + 'encryptKey', + 'Error', + 'error' + ) + ); + }) + .then(response => response.json()) + .then(json => { + dispatch( + triggerToaster( + 'Passphrase successfully encrypted', + 'Success', + 'success' + ) + ); + }) + } +} + +export function loginWithPin(key, pubKey) { + const payload = { + key: key, + pubkey: pubKey, + }; + + return dispatch => { + return fetch(`http://127.0.0.1:${Config.agamaPort}/shepherd/decryptkey`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(payload), + }) + .catch(function(error) { + console.log(error); + dispatch( + triggerToaster( + 'decryptKey', + 'Error', + 'error' + ) + ); + }) + .then(response => response.json()) + .then(json => { + dispatch(iguanaWalletPassphrase(json.result)); + }) + } +} + +export function loadPinList() { + return dispatch => { + return fetch(`http://127.0.0.1:${Config.agamaPort}/shepherd/getpinlist`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + } + }) + .catch(function(error) { + console.log(error); + dispatch( + triggerToaster( + 'getPinList', + 'Error', + 'error' + ) + ); + }) + .then(response => response.json()) + .then(json => { + dispatch( + triggerToaster( + 'getPinList', + 'Success', + 'success' + ) + ); + dispatch( + getPinList(json.result) + ) + }) + } +} \ No newline at end of file diff --git a/react/src/actions/storeType.js b/react/src/actions/storeType.js index 7a7bdfbe0..e7e14443f 100644 --- a/react/src/actions/storeType.js +++ b/react/src/actions/storeType.js @@ -46,4 +46,5 @@ export const LOGOUT = 'LOGOUT'; export const DISPLAY_COIND_DOWN_MODAL = 'DISPLAY_COIND_DOWN_MODAL'; export const DISPLAY_LOGIN_SETTINGS_MODAL = 'DISPLAY_LOGIN_SETTINGS_MODAL'; export const DISPLAY_CLAIM_INTEREST_MODAL = 'DISPLAY_CLAIM_INTEREST_MODAL'; +export const GET_PIN_LIST = 'GET_PIN_LIST'; export const DISPLAY_IMPORT_KEY_MODAL = 'DISPLAY_IMPORT_KEY_MODAL'; \ No newline at end of file diff --git a/react/src/components/app/app.js b/react/src/components/app/app.js index 75b39926d..5fa20d09a 100644 --- a/react/src/components/app/app.js +++ b/react/src/components/app/app.js @@ -5,6 +5,7 @@ import Main from '../main/main'; function mapStateToProps(state) { return { + login: state.login, toaster: state.toaster, AddCoin: state.AddCoin, Main: state.Main, diff --git a/react/src/components/login/login.js b/react/src/components/login/login.js index 9739b743c..a5a3afbd1 100644 --- a/react/src/components/login/login.js +++ b/react/src/components/login/login.js @@ -18,6 +18,11 @@ import { PassPhraseGenerator } from '../../util/crypto/passphrasegenerator'; import SwallModalRender from './swall-modal.render'; import LoginRender from './login.render'; import { translate } from '../../translate/translate'; +import { + encryptPassphrase, + loadPinList, + loginWithPin +} from '../../actions/actions/pin'; const IGUNA_ACTIVE_HANDLE_TIMEOUT = 3000; const IGUNA_ACTIVE_COINS_TIMEOUT = 10000; @@ -45,6 +50,11 @@ class Login extends React.Component { trimPassphraseTimer: null, displayLoginSettingsDropdown: false, displayLoginSettingsDropdownSection: null, + shouldEncryptSeed: false, + encryptKey: '', + pubKey: '', + decryptKey: '', + selectedPin: '', isExperimentalOn: false, }; this.toggleActivateCoinForm = this.toggleActivateCoinForm.bind(this); @@ -59,6 +69,10 @@ class Login extends React.Component { this.execWalletCreate = this.execWalletCreate.bind(this); this.resizeLoginTextarea = this.resizeLoginTextarea.bind(this); this.toggleLoginSettingsDropdown = this.toggleLoginSettingsDropdown.bind(this); + this.updateEncryptKey = this.updateEncryptKey.bind(this); + this.updatePubKey = this.updatePubKey.bind(this); + this.updateDecryptKey = this.updateDecryptKey.bind(this); + this.loadPinList = this.loadPinList.bind(this); } // the setInterval handler for 'activeCoins' @@ -98,6 +112,35 @@ class Login extends React.Component { }); } + shouldEncryptSeed() { + return this.state.shouldEncryptSeed; + } + + toggleShouldEncryptSeed() { + this.setState({ + shouldEncryptSeed: !this.state.shouldEncryptSeed + }); + } + + updateEncryptKey(e) { + this.setState({ + encryptKey: e.target.value + }); + } + + updatePubKey(e) { + this.setState({ + pubKey: e.target.value + }); + } + + + updateDecryptKey(e) { + this.setState({ + decryptKey: e.target.value + }); + } + openSyncOnlyModal() { Store.dispatch(getSyncOnlyForks()); @@ -119,6 +162,8 @@ class Login extends React.Component { componentDidMount() { Store.dispatch(iguanaActiveHandle(true)); + // this.loadPinList(); + let appConfig; try { @@ -153,6 +198,9 @@ class Login extends React.Component { } componentWillReceiveProps(props) { + if (props.Login.pinList === 'no pins') { + props.Login.pinList = []; + } if (props && props.Main && props.Main.isLoggedIn) { @@ -255,9 +303,27 @@ class Login extends React.Component { loginPassPhraseSeedType: null, }); - Store.dispatch( - iguanaWalletPassphrase(this.state.loginPassphrase) - ); + if (this.state.shouldEncryptSeed) { + Store.dispatch(encryptPassphrase(this.state.loginPassphrase, this.state.encryptKey, this.state.pubKey)); + } + + if (this.state.selectedPin) { + Store.dispatch(loginWithPin(this.state.decryptKey, this.state.selectedPin)); + } else { + Store.dispatch( + iguanaWalletPassphrase(this.state.loginPassphrase) + ); + } + } + + loadPinList() { + Store.dispatch(loadPinList()); + } + + updateSelectedPin(e) { + this.setState({ + selectedPin: e.target.value + }); } getLoginPassPhraseSeedType(passPhrase) { @@ -405,9 +471,9 @@ const mapStateToProps = (state) => { }, Interval: { interval: state.Interval.interval, - } + }, + Login: state.Login, }; - }; export default connect(mapStateToProps)(Login); diff --git a/react/src/components/login/login.render.js b/react/src/components/login/login.render.js index 0f70929f0..e6a5af4de 100644 --- a/react/src/components/login/login.render.js +++ b/react/src/components/login/login.render.js @@ -52,6 +52,9 @@ const LoginRender = function () {