recommit
This commit is contained in:
parent
bca759b522
commit
c2b881e10e
24 changed files with 625 additions and 16 deletions
|
@ -276,6 +276,18 @@ export const icons = {
|
||||||
<polyline points="17 6 23 6 23 12" />
|
<polyline points="17 6 23 6 23 12" />
|
||||||
</g>
|
</g>
|
||||||
),
|
),
|
||||||
|
[ICONS.EYE]: buildIcon(
|
||||||
|
<g>
|
||||||
|
<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z" />
|
||||||
|
<circle cx="12" cy="12" r="3" />
|
||||||
|
</g>
|
||||||
|
),
|
||||||
|
[ICONS.EYE_OFF]: buildIcon(
|
||||||
|
<g>
|
||||||
|
<path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24" />
|
||||||
|
<line x1="1" y1="1" x2="23" y2="23" />
|
||||||
|
</g>
|
||||||
|
),
|
||||||
[ICONS.VIEW]: buildIcon(
|
[ICONS.VIEW]: buildIcon(
|
||||||
<g>
|
<g>
|
||||||
<path d="M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4" />
|
<path d="M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4" />
|
||||||
|
|
68
src/ui/component/walletSecurityAndSync/index.js
Normal file
68
src/ui/component/walletSecurityAndSync/index.js
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
import * as SETTINGS from 'constants/settings';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import {
|
||||||
|
doWalletStatus,
|
||||||
|
doWalletEncrypt,
|
||||||
|
doWalletDecrypt,
|
||||||
|
selectWalletEncryptSucceeded,
|
||||||
|
selectWalletEncryptPending,
|
||||||
|
selectWalletEncryptResult,
|
||||||
|
selectWalletIsEncrypted,
|
||||||
|
selectHasTransactions,
|
||||||
|
} from 'lbry-redux';
|
||||||
|
import { doPasswordSaved } from 'redux/actions/app';
|
||||||
|
import WalletSecurityAndSync from './view';
|
||||||
|
import {
|
||||||
|
doCheckSync,
|
||||||
|
doGetSync,
|
||||||
|
doSetDefaultAccount,
|
||||||
|
doSyncApply,
|
||||||
|
selectHasSyncedWallet,
|
||||||
|
selectGetSyncIsPending,
|
||||||
|
selectSetSyncIsPending,
|
||||||
|
selectSyncApplyIsPending,
|
||||||
|
selectSyncApplyErrorMessage,
|
||||||
|
selectSyncData,
|
||||||
|
selectSyncHash,
|
||||||
|
selectHashChanged,
|
||||||
|
selectUser,
|
||||||
|
} from 'lbryinc';
|
||||||
|
import { selectIsPasswordSaved } from 'redux/selectors/app';
|
||||||
|
import { doSetClientSetting } from 'redux/actions/settings';
|
||||||
|
import { makeSelectClientSetting } from 'redux/selectors/settings';
|
||||||
|
|
||||||
|
const select = state => ({
|
||||||
|
walletEncryptSucceeded: selectWalletEncryptSucceeded(state),
|
||||||
|
walletEncryptPending: selectWalletEncryptPending(state),
|
||||||
|
walletEncryptResult: selectWalletEncryptResult(state),
|
||||||
|
walletEncrypted: selectWalletIsEncrypted(state),
|
||||||
|
walletHasTransactions: selectHasTransactions(state),
|
||||||
|
user: selectUser(state),
|
||||||
|
syncEnabled: makeSelectClientSetting(SETTINGS.ENABLE_SYNC)(state),
|
||||||
|
hasSyncedWallet: selectHasSyncedWallet(state),
|
||||||
|
getSyncIsPending: selectGetSyncIsPending(state),
|
||||||
|
setSyncIsPending: selectSetSyncIsPending(state),
|
||||||
|
syncApplyIsPending: selectSyncApplyIsPending(state),
|
||||||
|
syncApplyErrorMessage: selectSyncApplyErrorMessage(state),
|
||||||
|
syncData: selectSyncData(state),
|
||||||
|
syncHash: selectSyncHash(state),
|
||||||
|
isPasswordSaved: selectIsPasswordSaved(state),
|
||||||
|
hashChanged: selectHashChanged(state),
|
||||||
|
});
|
||||||
|
|
||||||
|
const perform = dispatch => ({
|
||||||
|
encryptWallet: password => dispatch(doWalletEncrypt(password)),
|
||||||
|
decryptWallet: () => dispatch(doWalletDecrypt()),
|
||||||
|
updateWalletStatus: () => dispatch(doWalletStatus()),
|
||||||
|
setPasswordSaved: saved => dispatch(doPasswordSaved(saved)),
|
||||||
|
syncApply: (hash, data, password) => dispatch(doSyncApply(hash, data, password)),
|
||||||
|
getSync: password => dispatch(doGetSync(password)),
|
||||||
|
checkSync: () => dispatch(doCheckSync()),
|
||||||
|
setDefaultAccount: () => dispatch(doSetDefaultAccount()),
|
||||||
|
setClientSetting: (key, value) => dispatch(doSetClientSetting(key, value)),
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(
|
||||||
|
select,
|
||||||
|
perform
|
||||||
|
)(WalletSecurityAndSync);
|
340
src/ui/component/walletSecurityAndSync/view.jsx
Normal file
340
src/ui/component/walletSecurityAndSync/view.jsx
Normal file
|
@ -0,0 +1,340 @@
|
||||||
|
// @flow
|
||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import { Form, FormField, Submit } from 'component/common/form';
|
||||||
|
import Button from 'component/button';
|
||||||
|
import UserEmail from 'component/userEmail';
|
||||||
|
import * as ICONS from 'constants/icons';
|
||||||
|
|
||||||
|
import { getSavedPassword, setSavedPassword, deleteSavedPassword } from 'util/saved-passwords';
|
||||||
|
// import { AUTH_ORG } from 'constants/keychain';
|
||||||
|
|
||||||
|
/*
|
||||||
|
On mount: checkSync()
|
||||||
|
if
|
||||||
|
Display on mount
|
||||||
|
if !email
|
||||||
|
SyncWallet.disabled = true
|
||||||
|
SyncWallet.checked = false
|
||||||
|
if walletEncrypted
|
||||||
|
EncryptWallet.checked = true
|
||||||
|
password = savedPassword ? savedPassword : ''
|
||||||
|
rememberPassword.checked = savedPassword
|
||||||
|
if !walletEncrypted
|
||||||
|
password = savedPassword ? savedPassword : ''
|
||||||
|
rememberPassword.checked = savedPassword
|
||||||
|
else email
|
||||||
|
if walletEncrypted
|
||||||
|
EncryptWallet.checked = true
|
||||||
|
password = savedPassword ? savedPassword : ''
|
||||||
|
rememberPassword.checked = savedPassword
|
||||||
|
syncEnabled = settings.syncEnabled
|
||||||
|
if syncEnabled
|
||||||
|
message = 'hi'
|
||||||
|
else
|
||||||
|
message = 'hi'
|
||||||
|
else if !walletEncrypted
|
||||||
|
EncryptWallet.checked = false
|
||||||
|
password = savedPassword ? savedPassword : ''
|
||||||
|
rememberPassword.checked = savedPassword
|
||||||
|
syncEnabled = settings.syncEnabled
|
||||||
|
if syncEnabled
|
||||||
|
message = 'hi'
|
||||||
|
else
|
||||||
|
message = 'hi'
|
||||||
|
*/
|
||||||
|
type Props = {
|
||||||
|
// wallet statuses
|
||||||
|
walletEncryptSucceeded: boolean,
|
||||||
|
walletEncryptPending: boolean,
|
||||||
|
walletDecryptSucceeded: boolean,
|
||||||
|
walletDecryptPending: boolean,
|
||||||
|
updateWalletStatus: boolean,
|
||||||
|
walletEncrypted: boolean,
|
||||||
|
// wallet methods
|
||||||
|
encryptWallet: (?string) => void,
|
||||||
|
decryptWallet: (?string) => void,
|
||||||
|
updateWalletStatus: () => void,
|
||||||
|
// housekeeping
|
||||||
|
setPasswordSaved: () => void,
|
||||||
|
syncEnabled: boolean,
|
||||||
|
setClientSetting: (string, boolean | string) => void,
|
||||||
|
isPasswordSaved: boolean,
|
||||||
|
// data
|
||||||
|
user: any,
|
||||||
|
// sync statuses
|
||||||
|
hasSyncedWallet: boolean,
|
||||||
|
getSyncIsPending?: boolean,
|
||||||
|
syncApplyErrorMessage?: string,
|
||||||
|
hashChanged: boolean,
|
||||||
|
// sync data
|
||||||
|
syncData: string | null,
|
||||||
|
syncHash: string | null,
|
||||||
|
// sync methods
|
||||||
|
syncApply: (string | null, string | null, string) => void,
|
||||||
|
checkSync: () => void,
|
||||||
|
setDefaultAccount: () => void,
|
||||||
|
hasTransactions: boolean,
|
||||||
|
};
|
||||||
|
|
||||||
|
type State = {
|
||||||
|
newPassword: string,
|
||||||
|
newPasswordConfirm: string,
|
||||||
|
passwordMatch: boolean,
|
||||||
|
understandConfirmed: boolean,
|
||||||
|
understandError: boolean,
|
||||||
|
submitted: boolean,
|
||||||
|
failMessage: ?string,
|
||||||
|
rememberPassword: boolean,
|
||||||
|
showEmailReg: boolean,
|
||||||
|
failed: boolean,
|
||||||
|
enableSync: boolean,
|
||||||
|
encryptWallet: boolean,
|
||||||
|
obscurePassword: boolean,
|
||||||
|
};
|
||||||
|
|
||||||
|
function WalletSecurityAndSync(props: Props) {
|
||||||
|
const {
|
||||||
|
// walletEncryptSucceeded,
|
||||||
|
// walletEncryptPending,
|
||||||
|
// walletDecryptSucceeded,
|
||||||
|
// walletDecryptPending,
|
||||||
|
// updateWalletStatus,
|
||||||
|
walletEncrypted,
|
||||||
|
encryptWallet,
|
||||||
|
decryptWallet,
|
||||||
|
// setPasswordSaved,
|
||||||
|
syncEnabled,
|
||||||
|
// setClientSetting,
|
||||||
|
// isPasswordSaved,
|
||||||
|
user,
|
||||||
|
hasSyncedWallet,
|
||||||
|
getSyncIsPending,
|
||||||
|
syncApplyErrorMessage,
|
||||||
|
hashChanged,
|
||||||
|
syncData,
|
||||||
|
syncHash,
|
||||||
|
syncApply,
|
||||||
|
checkSync,
|
||||||
|
hasTransactions,
|
||||||
|
// setDefaultAccount,
|
||||||
|
} = props;
|
||||||
|
|
||||||
|
const defaultComponentState: State = {
|
||||||
|
newPassword: '',
|
||||||
|
newPasswordConfirm: '',
|
||||||
|
passwordMatch: false,
|
||||||
|
understandConfirmed: false,
|
||||||
|
understandError: false,
|
||||||
|
submitted: false, // Prior actions could be marked complete
|
||||||
|
failMessage: undefined,
|
||||||
|
rememberPassword: false,
|
||||||
|
showEmailReg: false,
|
||||||
|
failed: false,
|
||||||
|
enableSync: syncEnabled,
|
||||||
|
encryptWallet: walletEncrypted,
|
||||||
|
obscurePassword: true,
|
||||||
|
};
|
||||||
|
const [componentState, setComponentState] = useState<State>(defaultComponentState);
|
||||||
|
|
||||||
|
const safeToSync = !hasTransactions || !hashChanged;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
checkSync();
|
||||||
|
}, []);
|
||||||
|
useEffect(() => {
|
||||||
|
setComponentState({
|
||||||
|
...componentState,
|
||||||
|
passwordMatch: componentState.newPassword === componentState.newPasswordConfirm,
|
||||||
|
});
|
||||||
|
}, [componentState.newPassword, componentState.newPasswordConfirm]);
|
||||||
|
|
||||||
|
const isEmailVerified = user && user.primary_email && user.has_verified_email;
|
||||||
|
// const syncDisabledMessage = 'You cannot sync without an email';
|
||||||
|
|
||||||
|
function onChangeNewPassword(event: SyntheticInputEvent<>) {
|
||||||
|
setComponentState({ ...componentState, newPassword: event.target.value });
|
||||||
|
}
|
||||||
|
|
||||||
|
function onChangeRememberPassword(event: SyntheticInputEvent<>) {
|
||||||
|
setComponentState({ ...componentState, rememberPassword: event.target.checked });
|
||||||
|
}
|
||||||
|
|
||||||
|
function onChangeNewPasswordConfirm(event: SyntheticInputEvent<>) {
|
||||||
|
setComponentState({ ...componentState, newPasswordConfirm: event.target.value });
|
||||||
|
}
|
||||||
|
|
||||||
|
function onChangeUnderstandConfirm(event: SyntheticInputEvent<>) {
|
||||||
|
setComponentState({ ...componentState, understandConfirmed: /^.?i understand.?$/i.test(event.target.value) });
|
||||||
|
}
|
||||||
|
|
||||||
|
function onChangeSync(event: SyntheticInputEvent<>) {
|
||||||
|
setComponentState({ ...componentState, enableSync: event.target.checked });
|
||||||
|
}
|
||||||
|
|
||||||
|
function onChangeEncrypt(event: SyntheticInputEvent<>) {
|
||||||
|
setComponentState({ ...componentState, encryptWallet: event.target.checked });
|
||||||
|
}
|
||||||
|
|
||||||
|
async function apply() {
|
||||||
|
setComponentState({ ...componentState, failed: false });
|
||||||
|
|
||||||
|
await checkSync();
|
||||||
|
if (componentState.enableSync) {
|
||||||
|
await syncApply(syncHash, syncData, componentState.newPassword);
|
||||||
|
if (syncApplyErrorMessage) {
|
||||||
|
setComponentState({ ...componentState, failed: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await decryptWallet();
|
||||||
|
if (componentState.failed !== true) {
|
||||||
|
await encryptWallet(componentState.newPassword);
|
||||||
|
}
|
||||||
|
if (componentState.encryptWallet) {
|
||||||
|
await encryptWallet(componentState.newPassword);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (componentState.failed === false) {
|
||||||
|
}
|
||||||
|
// this.setState({ submitted: true });
|
||||||
|
// this.props.encryptWallet(state.newPassword);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className="card card--section">
|
||||||
|
<h2 className="card__title">{__('Wallet Sync and Security')}</h2>
|
||||||
|
{!isEmailVerified && (
|
||||||
|
<React.Fragment>
|
||||||
|
<p className="card__subtitle">
|
||||||
|
{__(`It looks like we don't have your email.`)}{' '}
|
||||||
|
<Button
|
||||||
|
button="link"
|
||||||
|
label={__('Verify your email')}
|
||||||
|
onClick={() => setComponentState({ ...componentState, showEmailReg: !componentState.showEmailReg })}
|
||||||
|
/>{' '}
|
||||||
|
{__(`and then come back here.`)}
|
||||||
|
</p>
|
||||||
|
{componentState.showEmailReg && <UserEmail />}
|
||||||
|
</React.Fragment>
|
||||||
|
)}
|
||||||
|
<Form onSubmit={() => apply()}>
|
||||||
|
<p>
|
||||||
|
{__(
|
||||||
|
'Your LBRY password can help you encrypt your wallet or sync it to another device. You must use the same LBRY password on every device if you wish to sync.'
|
||||||
|
)}{' '}
|
||||||
|
<Button button="link" label={__('Learn more')} href="https://lbry.com/faq/wallet-encryption" />.
|
||||||
|
</p>
|
||||||
|
<fieldset-section>
|
||||||
|
<FormField
|
||||||
|
autoFocus
|
||||||
|
inputButton={
|
||||||
|
<Button
|
||||||
|
icon={componentState.obscurePassword ? ICONS.EYE : ICONS.EYE_OFF}
|
||||||
|
button={'primary'}
|
||||||
|
onClick={() =>
|
||||||
|
setComponentState({ ...componentState, obscurePassword: !componentState.obscurePassword })
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label={__('Password')}
|
||||||
|
placeholder={__('Shh...')}
|
||||||
|
type={componentState.obscurePassword ? 'password' : 'text'}
|
||||||
|
name="wallet-new-password"
|
||||||
|
onChange={event => onChangeNewPassword(event)}
|
||||||
|
/>
|
||||||
|
</fieldset-section>
|
||||||
|
<fieldset-section>
|
||||||
|
<FormField
|
||||||
|
error={componentState.passwordMatch === false ? 'No match' : false}
|
||||||
|
label={__('Same Password')}
|
||||||
|
placeholder={__('Your eyes only')}
|
||||||
|
type="password"
|
||||||
|
name="wallet-new-password-confirm"
|
||||||
|
onChange={event => onChangeNewPasswordConfirm(event)}
|
||||||
|
/>
|
||||||
|
</fieldset-section>
|
||||||
|
|
||||||
|
<fieldset-section>
|
||||||
|
<FormField
|
||||||
|
label={__('Remember Password')}
|
||||||
|
type="checkbox"
|
||||||
|
name="wallet-remember-password"
|
||||||
|
onChange={event => onChangeRememberPassword(event)}
|
||||||
|
checked={componentState.rememberPassword}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
type="checkbox"
|
||||||
|
name="encrypt_enabled"
|
||||||
|
checked={componentState.encryptWallet}
|
||||||
|
disabled={false}
|
||||||
|
onChange={event => onChangeEncrypt(event)}
|
||||||
|
label={__('Encrypt Wallet')}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<FormField
|
||||||
|
type="checkbox"
|
||||||
|
name="sync_enabled"
|
||||||
|
checked={componentState.enableSync}
|
||||||
|
disabled={!isEmailVerified || !safeToSync}
|
||||||
|
error={!!syncApplyErrorMessage && syncApplyErrorMessage}
|
||||||
|
helper={!!syncApplyErrorMessage && syncApplyErrorMessage}
|
||||||
|
prefix={<span className="badge badge--alert">ALPHA</span>}
|
||||||
|
onChange={event => onChangeSync(event)}
|
||||||
|
label={
|
||||||
|
<React.Fragment>
|
||||||
|
{__('Enable Sync')} <Button button="link" label={__('(?)')} href="https://lbry.com/privacypolicy" />{' '}
|
||||||
|
<span className="badge badge--alert">ALPHA</span>
|
||||||
|
</React.Fragment>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</fieldset-section>
|
||||||
|
|
||||||
|
<div className="card__subtitle--status">
|
||||||
|
{__(
|
||||||
|
'If your password is lost, it cannot be recovered. You will not be able to access your wallet without a password.'
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<FormField
|
||||||
|
error={componentState.understandError === true ? 'You must enter "I understand"' : false}
|
||||||
|
label={__('Enter "I understand"')}
|
||||||
|
placeholder={__('I understand')}
|
||||||
|
type="text"
|
||||||
|
name="wallet-understand"
|
||||||
|
onChange={event => onChangeUnderstandConfirm(event)}
|
||||||
|
/>
|
||||||
|
{componentState.failMessage && <div className="error-text">{__(componentState.failMessage)}</div>}
|
||||||
|
<Submit
|
||||||
|
disabled={!componentState.passwordMatch}
|
||||||
|
label={componentState.failMessage ? __('Encrypting Wallet') : __('Apply')}
|
||||||
|
/>
|
||||||
|
</Form>
|
||||||
|
testing stuff
|
||||||
|
<Button
|
||||||
|
button="primary"
|
||||||
|
label={__('Sync Apply')}
|
||||||
|
onClick={() => syncApply(syncHash, syncData, componentState.newPassword)}
|
||||||
|
/>{' '}
|
||||||
|
<Button button="primary" label={__('Check Sync')} onClick={() => checkSync()} />{' '}
|
||||||
|
<Button button="primary" label={__('Setpass test')} onClick={() => setSavedPassword('test', 'testpass')} />{' '}
|
||||||
|
<Button
|
||||||
|
button="primary"
|
||||||
|
label={__('Getpass test')}
|
||||||
|
onClick={() => getSavedPassword('test').then(p => setComponentState({ ...componentState, newPassword: p }))}
|
||||||
|
/>{' '}
|
||||||
|
<Button button="primary" label={__('Deletepass test')} onClick={() => deleteSavedPassword('test')} />{' '}
|
||||||
|
<p>password: {componentState.newPassword}</p>
|
||||||
|
<p>encryptWallet: {String(componentState.encryptWallet)}</p>
|
||||||
|
<p>enableSync: {String(componentState.enableSync)}</p>
|
||||||
|
<p>syncApplyError: {String(syncApplyErrorMessage)}</p>
|
||||||
|
<p>Has Synced: {String(hasSyncedWallet)}</p>
|
||||||
|
<p>getSyncPending: {String(getSyncIsPending)}</p>
|
||||||
|
<p>syncEnabled: {String(syncEnabled)}</p>
|
||||||
|
<p>syncHash: {syncHash ? syncHash.slice(0, 10) : 'null'}</p>
|
||||||
|
<p>syncData: {syncData ? syncData.slice(0, 10) : 'null'}</p>
|
||||||
|
<p>walletEncrypted: {String(walletEncrypted)}</p>
|
||||||
|
<p>emailRegistered: {String(isEmailVerified)}</p>
|
||||||
|
<p>hashChanged: {String(hashChanged)}</p>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default WalletSecurityAndSync;
|
|
@ -19,6 +19,7 @@ export const SHOW_MODAL = 'SHOW_MODAL';
|
||||||
export const HIDE_MODAL = 'HIDE_MODAL';
|
export const HIDE_MODAL = 'HIDE_MODAL';
|
||||||
export const CHANGE_MODALS_ALLOWED = 'CHANGE_MODALS_ALLOWED';
|
export const CHANGE_MODALS_ALLOWED = 'CHANGE_MODALS_ALLOWED';
|
||||||
export const TOGGLE_SEARCH_EXPANDED = 'TOGGLE_SEARCH_EXPANDED';
|
export const TOGGLE_SEARCH_EXPANDED = 'TOGGLE_SEARCH_EXPANDED';
|
||||||
|
export const PASSWORD_SAVED = 'PASSWORD_SAVED';
|
||||||
|
|
||||||
// Navigation
|
// Navigation
|
||||||
export const CHANGE_AFTER_AUTH_PATH = 'CHANGE_AFTER_AUTH_PATH';
|
export const CHANGE_AFTER_AUTH_PATH = 'CHANGE_AFTER_AUTH_PATH';
|
||||||
|
|
|
@ -73,3 +73,5 @@ export const SUPPORT = 'TrendingUp';
|
||||||
export const BLOCK = 'Slash';
|
export const BLOCK = 'Slash';
|
||||||
export const UNBLOCK = 'Circle';
|
export const UNBLOCK = 'Circle';
|
||||||
export const VIEW = 'View';
|
export const VIEW = 'View';
|
||||||
|
export const EYE = 'Eye';
|
||||||
|
export const EYE_OFF = 'EyeOff';
|
||||||
|
|
3
src/ui/constants/keychain.js
Normal file
3
src/ui/constants/keychain.js
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
export const AUTH_ORG = 'LBRY';
|
||||||
|
export const KEY_WALLET_PASSWORD = 'wallet_password';
|
||||||
|
export const KEY_AUTH_TOKEN = 'auth_token';
|
|
@ -28,3 +28,5 @@ export const CONFIRM_THUMBNAIL_UPLOAD = 'confirm_thumbnail_upload';
|
||||||
export const WALLET_ENCRYPT = 'wallet_encrypt';
|
export const WALLET_ENCRYPT = 'wallet_encrypt';
|
||||||
export const WALLET_DECRYPT = 'wallet_decrypt';
|
export const WALLET_DECRYPT = 'wallet_decrypt';
|
||||||
export const WALLET_UNLOCK = 'wallet_unlock';
|
export const WALLET_UNLOCK = 'wallet_unlock';
|
||||||
|
export const WALLET_SYNC = 'wallet_sync';
|
||||||
|
export const WALLET_PASSWORD_UNSAVE = 'wallet_password_unsave';
|
||||||
|
|
15
src/ui/modal/modalPasswordUnsave/index.js
Normal file
15
src/ui/modal/modalPasswordUnsave/index.js
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import ModalPasswordUnsave from './view';
|
||||||
|
import { doHideModal, doPasswordSaved } from 'redux/actions/app';
|
||||||
|
|
||||||
|
// const select = () => ({});
|
||||||
|
//
|
||||||
|
const perform = dispatch => ({
|
||||||
|
closeModal: () => dispatch(doHideModal()),
|
||||||
|
setPasswordSaved: saved => dispatch(doPasswordSaved(saved)),
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(
|
||||||
|
null,
|
||||||
|
perform
|
||||||
|
)(ModalPasswordUnsave);
|
38
src/ui/modal/modalPasswordUnsave/view.jsx
Normal file
38
src/ui/modal/modalPasswordUnsave/view.jsx
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
// @flow
|
||||||
|
import React from 'react';
|
||||||
|
import { Modal } from 'modal/modal';
|
||||||
|
import keytar from 'keytar';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
closeModal: () => void,
|
||||||
|
setPasswordSaved: boolean => void,
|
||||||
|
};
|
||||||
|
|
||||||
|
class ModalPasswordUnsave extends React.PureComponent<Props> {
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
isOpen
|
||||||
|
contentLabel={__('Unsave Password')}
|
||||||
|
title={__('Clear Saved Password')}
|
||||||
|
type="confirm"
|
||||||
|
confirmButtonLabel={__('Forget')}
|
||||||
|
abortButtonLabel={__('Nevermind')}
|
||||||
|
onConfirmed={() =>
|
||||||
|
keytar.deletePassword('LBRY', 'wallet_password').then(() => {
|
||||||
|
this.props.setPasswordSaved(false);
|
||||||
|
this.props.closeModal();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
onAborted={this.props.closeModal}
|
||||||
|
>
|
||||||
|
<p>
|
||||||
|
{__('You are about to delete your saved password.')}{' '}
|
||||||
|
{__('Your wallet will still be encrypted, but you will have to remember and enter it manually on startup.')}
|
||||||
|
</p>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ModalPasswordUnsave;
|
|
@ -28,6 +28,7 @@ import ModalWalletEncrypt from 'modal/modalWalletEncrypt';
|
||||||
import ModalWalletDecrypt from 'modal/modalWalletDecrypt';
|
import ModalWalletDecrypt from 'modal/modalWalletDecrypt';
|
||||||
import ModalWalletUnlock from 'modal/modalWalletUnlock';
|
import ModalWalletUnlock from 'modal/modalWalletUnlock';
|
||||||
import ModalRewardCode from 'modal/modalRewardCode';
|
import ModalRewardCode from 'modal/modalRewardCode';
|
||||||
|
import ModalPasswordUnsave from 'modal/modalPasswordUnsave';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
modal: { id: string, modalProps: {} },
|
modal: { id: string, modalProps: {} },
|
||||||
|
@ -100,6 +101,8 @@ function ModalRouter(props: Props) {
|
||||||
return <ModalWalletDecrypt {...modalProps} />;
|
return <ModalWalletDecrypt {...modalProps} />;
|
||||||
case MODALS.WALLET_UNLOCK:
|
case MODALS.WALLET_UNLOCK:
|
||||||
return <ModalWalletUnlock {...modalProps} />;
|
return <ModalWalletUnlock {...modalProps} />;
|
||||||
|
case MODALS.WALLET_PASSWORD_UNSAVE:
|
||||||
|
return <ModalPasswordUnsave {...modalProps} />;
|
||||||
case MODALS.REWARD_GENERATED_CODE:
|
case MODALS.REWARD_GENERATED_CODE:
|
||||||
return <ModalRewardCode {...modalProps} />;
|
return <ModalRewardCode {...modalProps} />;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -1,16 +1,19 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { doWalletStatus, doWalletDecrypt, selectWalletDecryptSucceeded } from 'lbry-redux';
|
import { doWalletStatus, doWalletDecrypt, selectWalletDecryptSucceeded } from 'lbry-redux';
|
||||||
import { doHideModal } from 'redux/actions/app';
|
import { doHideModal, doPasswordSaved } from 'redux/actions/app';
|
||||||
import ModalWalletDecrypt from './view';
|
import ModalWalletDecrypt from './view';
|
||||||
|
import { selectIsPasswordSaved } from 'redux/selectors/app';
|
||||||
|
|
||||||
const select = state => ({
|
const select = state => ({
|
||||||
walletDecryptSucceded: selectWalletDecryptSucceeded(state),
|
walletDecryptSucceded: selectWalletDecryptSucceeded(state),
|
||||||
|
isPasswordSaved: selectIsPasswordSaved(state),
|
||||||
});
|
});
|
||||||
|
|
||||||
const perform = dispatch => ({
|
const perform = dispatch => ({
|
||||||
closeModal: () => dispatch(doHideModal()),
|
closeModal: () => dispatch(doHideModal()),
|
||||||
decryptWallet: password => dispatch(doWalletDecrypt(password)),
|
decryptWallet: password => dispatch(doWalletDecrypt(password)),
|
||||||
updateWalletStatus: () => dispatch(doWalletStatus()),
|
updateWalletStatus: () => dispatch(doWalletStatus()),
|
||||||
|
setPasswordSaved: saved => dispatch(doPasswordSaved(saved)),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(
|
export default connect(
|
||||||
|
|
|
@ -2,12 +2,15 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Modal } from 'modal/modal';
|
import { Modal } from 'modal/modal';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
|
import keytar from 'keytar';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
closeModal: () => void,
|
closeModal: () => void,
|
||||||
decryptWallet: () => void,
|
decryptWallet: () => void,
|
||||||
updateWalletStatus: () => void,
|
updateWalletStatus: () => void,
|
||||||
walletDecryptSucceded: boolean,
|
walletDecryptSucceded: boolean,
|
||||||
|
passwordUnsaved: () => void,
|
||||||
|
setPasswordSaved: boolean => void,
|
||||||
};
|
};
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
|
@ -23,6 +26,8 @@ class ModalWalletDecrypt extends React.PureComponent<Props, State> {
|
||||||
const { props, state } = this;
|
const { props, state } = this;
|
||||||
|
|
||||||
if (state.submitted && props.walletDecryptSucceded === true) {
|
if (state.submitted && props.walletDecryptSucceded === true) {
|
||||||
|
keytar.deletePassword('LBRY', 'wallet_password');
|
||||||
|
props.setPasswordSaved(false);
|
||||||
props.closeModal();
|
props.closeModal();
|
||||||
props.updateWalletStatus();
|
props.updateWalletStatus();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,6 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import {
|
import { doWalletStatus, doWalletEncrypt, selectWalletEncryptSucceeded, selectWalletEncryptResult } from 'lbry-redux';
|
||||||
doWalletStatus,
|
import { doHideModal, doPasswordSaved } from 'redux/actions/app';
|
||||||
doWalletEncrypt,
|
|
||||||
selectWalletEncryptPending,
|
|
||||||
selectWalletEncryptSucceeded,
|
|
||||||
selectWalletEncryptResult,
|
|
||||||
} from 'lbry-redux';
|
|
||||||
import { doHideModal } from 'redux/actions/app';
|
|
||||||
import ModalWalletEncrypt from './view';
|
import ModalWalletEncrypt from './view';
|
||||||
|
|
||||||
const select = state => ({
|
const select = state => ({
|
||||||
|
@ -18,6 +12,7 @@ const perform = dispatch => ({
|
||||||
closeModal: () => dispatch(doHideModal()),
|
closeModal: () => dispatch(doHideModal()),
|
||||||
encryptWallet: password => dispatch(doWalletEncrypt(password)),
|
encryptWallet: password => dispatch(doWalletEncrypt(password)),
|
||||||
updateWalletStatus: () => dispatch(doWalletStatus()),
|
updateWalletStatus: () => dispatch(doWalletStatus()),
|
||||||
|
setPasswordSaved: saved => dispatch(doPasswordSaved(saved)),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(
|
export default connect(
|
||||||
|
|
|
@ -3,6 +3,7 @@ import React from 'react';
|
||||||
import { Form, FormField, Submit } from 'component/common/form';
|
import { Form, FormField, Submit } from 'component/common/form';
|
||||||
import { Modal } from 'modal/modal';
|
import { Modal } from 'modal/modal';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
|
import keytar from 'keytar';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
closeModal: () => void,
|
closeModal: () => void,
|
||||||
|
@ -10,6 +11,7 @@ type Props = {
|
||||||
updateWalletStatus: boolean,
|
updateWalletStatus: boolean,
|
||||||
encryptWallet: (?string) => void,
|
encryptWallet: (?string) => void,
|
||||||
updateWalletStatus: () => void,
|
updateWalletStatus: () => void,
|
||||||
|
setPasswordSaved: boolean => void,
|
||||||
};
|
};
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
|
@ -20,6 +22,7 @@ type State = {
|
||||||
understandError: boolean,
|
understandError: boolean,
|
||||||
submitted: boolean,
|
submitted: boolean,
|
||||||
failMessage: ?string,
|
failMessage: ?string,
|
||||||
|
rememberPassword: boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
class ModalWalletEncrypt extends React.PureComponent<Props, State> {
|
class ModalWalletEncrypt extends React.PureComponent<Props, State> {
|
||||||
|
@ -31,6 +34,7 @@ class ModalWalletEncrypt extends React.PureComponent<Props, State> {
|
||||||
understandError: false,
|
understandError: false,
|
||||||
submitted: false, // Prior actions could be marked complete
|
submitted: false, // Prior actions could be marked complete
|
||||||
failMessage: undefined,
|
failMessage: undefined,
|
||||||
|
rememberPassword: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
componentDidUpdate() {
|
componentDidUpdate() {
|
||||||
|
@ -51,6 +55,10 @@ class ModalWalletEncrypt extends React.PureComponent<Props, State> {
|
||||||
this.setState({ newPassword: event.target.value });
|
this.setState({ newPassword: event.target.value });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onChangeRememberPassword(event: SyntheticInputEvent<>) {
|
||||||
|
this.setState({ rememberPassword: event.target.checked });
|
||||||
|
}
|
||||||
|
|
||||||
onChangeNewPasswordConfirm(event: SyntheticInputEvent<>) {
|
onChangeNewPasswordConfirm(event: SyntheticInputEvent<>) {
|
||||||
this.setState({ newPasswordConfirm: event.target.value });
|
this.setState({ newPasswordConfirm: event.target.value });
|
||||||
}
|
}
|
||||||
|
@ -79,7 +87,10 @@ class ModalWalletEncrypt extends React.PureComponent<Props, State> {
|
||||||
if (invalidEntries === true) {
|
if (invalidEntries === true) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (state.rememberPassword === true) {
|
||||||
|
this.props.setPasswordSaved(true);
|
||||||
|
keytar.setPassword('LBRY', 'wallet_password', state.newPassword);
|
||||||
|
}
|
||||||
this.setState({ submitted: true });
|
this.setState({ submitted: true });
|
||||||
this.props.encryptWallet(state.newPassword);
|
this.props.encryptWallet(state.newPassword);
|
||||||
}
|
}
|
||||||
|
@ -88,7 +99,6 @@ class ModalWalletEncrypt extends React.PureComponent<Props, State> {
|
||||||
const { closeModal } = this.props;
|
const { closeModal } = this.props;
|
||||||
|
|
||||||
const { passwordMismatch, understandError, failMessage } = this.state;
|
const { passwordMismatch, understandError, failMessage } = this.state;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
isOpen
|
isOpen
|
||||||
|
@ -126,6 +136,15 @@ class ModalWalletEncrypt extends React.PureComponent<Props, State> {
|
||||||
onChange={event => this.onChangeNewPasswordConfirm(event)}
|
onChange={event => this.onChangeNewPasswordConfirm(event)}
|
||||||
/>
|
/>
|
||||||
</fieldset-section>
|
</fieldset-section>
|
||||||
|
<fieldset-section>
|
||||||
|
<FormField
|
||||||
|
label={__('Remember Password')}
|
||||||
|
type="checkbox"
|
||||||
|
name="wallet-remember-password"
|
||||||
|
onChange={event => this.onChangeRememberPassword(event)}
|
||||||
|
checked={this.state.rememberPassword}
|
||||||
|
/>
|
||||||
|
</fieldset-section>
|
||||||
|
|
||||||
<div className="card__subtitle--status">
|
<div className="card__subtitle--status">
|
||||||
{__(
|
{__(
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { doWalletUnlock, selectWalletUnlockPending, selectWalletUnlockSucceeded } from 'lbry-redux';
|
import { doWalletUnlock, selectWalletUnlockSucceeded } from 'lbry-redux';
|
||||||
import { doQuit, doHideModal } from 'redux/actions/app';
|
import { doQuit, doHideModal, doPasswordSaved } from 'redux/actions/app';
|
||||||
import ModalWalletUnlock from './view';
|
import ModalWalletUnlock from './view';
|
||||||
|
|
||||||
const select = state => ({
|
const select = state => ({
|
||||||
|
@ -11,6 +11,7 @@ const perform = dispatch => ({
|
||||||
closeModal: () => dispatch(doHideModal()),
|
closeModal: () => dispatch(doHideModal()),
|
||||||
quit: () => dispatch(doQuit()),
|
quit: () => dispatch(doQuit()),
|
||||||
unlockWallet: password => dispatch(doWalletUnlock(password)),
|
unlockWallet: password => dispatch(doWalletUnlock(password)),
|
||||||
|
setPasswordSaved: saved => dispatch(doPasswordSaved(saved)),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(
|
export default connect(
|
||||||
|
|
|
@ -3,27 +3,35 @@ import React from 'react';
|
||||||
import { Form, FormField } from 'component/common/form';
|
import { Form, FormField } from 'component/common/form';
|
||||||
import { Modal } from 'modal/modal';
|
import { Modal } from 'modal/modal';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
|
import keytar from 'keytar';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
quit: () => void,
|
quit: () => void,
|
||||||
closeModal: () => void,
|
closeModal: () => void,
|
||||||
unlockWallet: (?string) => void,
|
unlockWallet: (?string) => void,
|
||||||
walletUnlockSucceded: boolean,
|
walletUnlockSucceded: boolean,
|
||||||
|
setPasswordSaved: boolean => void,
|
||||||
};
|
};
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
password: string,
|
password: string,
|
||||||
|
rememberPassword: boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
class ModalWalletUnlock extends React.PureComponent<Props, State> {
|
class ModalWalletUnlock extends React.PureComponent<Props, State> {
|
||||||
state = {
|
state = {
|
||||||
password: '',
|
password: '',
|
||||||
|
rememberPassword: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
componentDidUpdate() {
|
componentDidUpdate() {
|
||||||
const { props } = this;
|
const { props } = this;
|
||||||
|
|
||||||
if (props.walletUnlockSucceded === true) {
|
if (props.walletUnlockSucceded === true) {
|
||||||
|
if (this.state.rememberPassword) {
|
||||||
|
this.props.setPasswordSaved(true);
|
||||||
|
keytar.setPassword('LBRY', 'wallet_password', this.state.password);
|
||||||
|
}
|
||||||
props.closeModal();
|
props.closeModal();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,11 +40,14 @@ class ModalWalletUnlock extends React.PureComponent<Props, State> {
|
||||||
this.setState({ password: event.target.value });
|
this.setState({ password: event.target.value });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onChangeRememberPassword(event: SyntheticInputEvent<>) {
|
||||||
|
this.setState({ rememberPassword: event.target.checked });
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { quit, unlockWallet, walletUnlockSucceded } = this.props;
|
const { quit, unlockWallet, walletUnlockSucceded } = this.props;
|
||||||
|
|
||||||
const { password } = this.state;
|
const { password, rememberPassword } = this.state;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
isOpen
|
isOpen
|
||||||
|
@ -61,7 +72,18 @@ class ModalWalletUnlock extends React.PureComponent<Props, State> {
|
||||||
type="password"
|
type="password"
|
||||||
name="wallet-password"
|
name="wallet-password"
|
||||||
onChange={event => this.onChangePassword(event)}
|
onChange={event => this.onChangePassword(event)}
|
||||||
|
value={password || ''}
|
||||||
/>
|
/>
|
||||||
|
<fieldset-section>
|
||||||
|
<FormField
|
||||||
|
label={__('Remember Password')}
|
||||||
|
type="checkbox"
|
||||||
|
name="wallet-remember-password"
|
||||||
|
onChange={event => this.onChangeRememberPassword(event)}
|
||||||
|
checked={rememberPassword}
|
||||||
|
helper={__('You will no longer see this at startup')}
|
||||||
|
/>
|
||||||
|
</fieldset-section>
|
||||||
</Form>
|
</Form>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { connect } from 'react-redux';
|
||||||
import * as SETTINGS from 'constants/settings';
|
import * as SETTINGS from 'constants/settings';
|
||||||
import { doClearCache, doNotifyEncryptWallet, doNotifyDecryptWallet } from 'redux/actions/app';
|
import { doClearCache, doNotifyEncryptWallet, doNotifyDecryptWallet } from 'redux/actions/app';
|
||||||
import { doSetDaemonSetting, doSetClientSetting, doGetThemes, doSetDarkTime } from 'redux/actions/settings';
|
import { doSetDaemonSetting, doSetClientSetting, doGetThemes, doSetDarkTime } from 'redux/actions/settings';
|
||||||
|
import { selectIsPasswordSaved } from 'redux/selectors/app';
|
||||||
import { doSetPlayingUri } from 'redux/actions/content';
|
import { doSetPlayingUri } from 'redux/actions/content';
|
||||||
import { makeSelectClientSetting, selectDaemonSettings, selectosNotificationsEnabled } from 'redux/selectors/settings';
|
import { makeSelectClientSetting, selectDaemonSettings, selectosNotificationsEnabled } from 'redux/selectors/settings';
|
||||||
import { doWalletStatus, selectWalletIsEncrypted, selectBlockedChannelsCount } from 'lbry-redux';
|
import { doWalletStatus, selectWalletIsEncrypted, selectBlockedChannelsCount } from 'lbry-redux';
|
||||||
|
@ -34,6 +35,8 @@ const perform = dispatch => ({
|
||||||
encryptWallet: () => dispatch(doNotifyEncryptWallet()),
|
encryptWallet: () => dispatch(doNotifyEncryptWallet()),
|
||||||
decryptWallet: () => dispatch(doNotifyDecryptWallet()),
|
decryptWallet: () => dispatch(doNotifyDecryptWallet()),
|
||||||
updateWalletStatus: () => dispatch(doWalletStatus()),
|
updateWalletStatus: () => dispatch(doWalletStatus()),
|
||||||
|
confirmForgetPassword: modalProps => dispatch(doNotifyForgetPassword(modalProps)),
|
||||||
|
setPasswordSaved: saved => dispatch(doPasswordSaved(saved)),
|
||||||
clearPlayingUri: () => dispatch(doSetPlayingUri(null)),
|
clearPlayingUri: () => dispatch(doSetPlayingUri(null)),
|
||||||
setDarkTime: (time, options) => dispatch(doSetDarkTime(time, options)),
|
setDarkTime: (time, options) => dispatch(doSetDarkTime(time, options)),
|
||||||
});
|
});
|
||||||
|
|
|
@ -11,6 +11,9 @@ import I18nMessage from 'component/i18nMessage';
|
||||||
import Page from 'component/page';
|
import Page from 'component/page';
|
||||||
import SettingLanguage from 'component/settingLanguage';
|
import SettingLanguage from 'component/settingLanguage';
|
||||||
import FileSelector from 'component/common/file-selector';
|
import FileSelector from 'component/common/file-selector';
|
||||||
|
import UnsupportedOnWeb from 'component/common/unsupported-on-web';
|
||||||
|
import keytar from 'keytar';
|
||||||
|
import WalletSecurityAndSync from '../../component/walletSecurityAndSync';
|
||||||
|
|
||||||
type Price = {
|
type Price = {
|
||||||
currency: string,
|
currency: string,
|
||||||
|
@ -60,6 +63,9 @@ type Props = {
|
||||||
supportOption: boolean,
|
supportOption: boolean,
|
||||||
userBlockedChannelsCount?: number,
|
userBlockedChannelsCount?: number,
|
||||||
hideBalance: boolean,
|
hideBalance: boolean,
|
||||||
|
confirmForgetPassword: () => void,
|
||||||
|
isPasswordSaved: boolean,
|
||||||
|
setPasswordSaved: boolean => void,
|
||||||
floatingPlayer: boolean,
|
floatingPlayer: boolean,
|
||||||
clearPlayingUri: () => void,
|
clearPlayingUri: () => void,
|
||||||
darkModeTimes: DarkModeTimes,
|
darkModeTimes: DarkModeTimes,
|
||||||
|
@ -68,6 +74,7 @@ type Props = {
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
clearingCache: boolean,
|
clearingCache: boolean,
|
||||||
|
storedPassword: boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
class SettingsPage extends React.PureComponent<Props, State> {
|
class SettingsPage extends React.PureComponent<Props, State> {
|
||||||
|
@ -76,6 +83,7 @@ class SettingsPage extends React.PureComponent<Props, State> {
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
clearingCache: false,
|
clearingCache: false,
|
||||||
|
storedPassword: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
(this: any).onKeyFeeChange = this.onKeyFeeChange.bind(this);
|
(this: any).onKeyFeeChange = this.onKeyFeeChange.bind(this);
|
||||||
|
@ -91,6 +99,13 @@ class SettingsPage extends React.PureComponent<Props, State> {
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.props.getThemes();
|
this.props.getThemes();
|
||||||
this.props.updateWalletStatus();
|
this.props.updateWalletStatus();
|
||||||
|
keytar.getPassword('LBRY', 'wallet_password').then(p => {
|
||||||
|
if (p || p === '') {
|
||||||
|
this.props.setPasswordSaved(true);
|
||||||
|
} else {
|
||||||
|
this.props.setPasswordSaved(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onKeyFeeChange(newValue: Price) {
|
onKeyFeeChange(newValue: Price) {
|
||||||
|
@ -137,6 +152,11 @@ class SettingsPage extends React.PureComponent<Props, State> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onConfirmForgetPassword() {
|
||||||
|
const { confirmForgetPassword } = this.props;
|
||||||
|
confirmForgetPassword();
|
||||||
|
}
|
||||||
|
|
||||||
onChangeTime(event: SyntheticInputEvent<*>, options: OptionTimes) {
|
onChangeTime(event: SyntheticInputEvent<*>, options: OptionTimes) {
|
||||||
const { value } = event.target;
|
const { value } = event.target;
|
||||||
|
|
||||||
|
@ -189,6 +209,7 @@ class SettingsPage extends React.PureComponent<Props, State> {
|
||||||
floatingPlayer,
|
floatingPlayer,
|
||||||
clearPlayingUri,
|
clearPlayingUri,
|
||||||
darkModeTimes,
|
darkModeTimes,
|
||||||
|
isPasswordSaved,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const noDaemonSettings = !daemonSettings || Object.keys(daemonSettings).length === 0;
|
const noDaemonSettings = !daemonSettings || Object.keys(daemonSettings).length === 0;
|
||||||
|
@ -229,6 +250,7 @@ class SettingsPage extends React.PureComponent<Props, State> {
|
||||||
<p className="help">{__('LBRY downloads will be saved here.')}</p>
|
<p className="help">{__('LBRY downloads will be saved here.')}</p>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
<WalletSecurityAndSync />
|
||||||
<section className="card card--section">
|
<section className="card card--section">
|
||||||
<h2 className="card__title">{__('Network and Data Settings')}</h2>
|
<h2 className="card__title">{__('Network and Data Settings')}</h2>
|
||||||
<Form>
|
<Form>
|
||||||
|
@ -497,7 +519,16 @@ class SettingsPage extends React.PureComponent<Props, State> {
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
{isPasswordSaved && (
|
||||||
|
<p className="card__subtitle card__help">
|
||||||
|
{__('Your password is saved in your OS keychain.')}{' '}
|
||||||
|
<Button
|
||||||
|
button="link"
|
||||||
|
label={__('I want to type it manually')}
|
||||||
|
onClick={this.onConfirmForgetPassword}
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
<FormField
|
<FormField
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
name="hide_balance"
|
name="hide_balance"
|
||||||
|
|
|
@ -20,6 +20,7 @@ import {
|
||||||
filteredReducer,
|
filteredReducer,
|
||||||
homepageReducer,
|
homepageReducer,
|
||||||
statsReducer,
|
statsReducer,
|
||||||
|
syncReducer,
|
||||||
} from 'lbryinc';
|
} from 'lbryinc';
|
||||||
import appReducer from 'redux/reducers/app';
|
import appReducer from 'redux/reducers/app';
|
||||||
import availabilityReducer from 'redux/reducers/availability';
|
import availabilityReducer from 'redux/reducers/availability';
|
||||||
|
@ -52,4 +53,5 @@ export default history =>
|
||||||
blocked: blockedReducer,
|
blocked: blockedReducer,
|
||||||
user: userReducer,
|
user: userReducer,
|
||||||
wallet: walletReducer,
|
wallet: walletReducer,
|
||||||
|
sync: syncReducer,
|
||||||
});
|
});
|
||||||
|
|
|
@ -307,12 +307,33 @@ export function doNotifyUnlockWallet() {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function doNotifyForgetPassword() {
|
||||||
|
return dispatch => {
|
||||||
|
dispatch(doOpenModal(MODALS.WALLET_PASSWORD_UNSAVE));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doNotifySyncWallet() {
|
||||||
|
return dispatch => {
|
||||||
|
dispatch(doOpenModal(MODALS.WALLET_SYNC));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function doAlertError(errorList) {
|
export function doAlertError(errorList) {
|
||||||
return dispatch => {
|
return dispatch => {
|
||||||
dispatch(doError(errorList));
|
dispatch(doError(errorList));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function doPasswordSaved(saved) {
|
||||||
|
return dispatch => {
|
||||||
|
dispatch({
|
||||||
|
type: ACTIONS.PASSWORD_SAVED,
|
||||||
|
data: saved,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function doDaemonReady() {
|
export function doDaemonReady() {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
|
|
|
@ -38,6 +38,7 @@ export type AppState = {
|
||||||
hasClickedComment: boolean,
|
hasClickedComment: boolean,
|
||||||
enhancedLayout: boolean,
|
enhancedLayout: boolean,
|
||||||
searchOptionsExpanded: boolean,
|
searchOptionsExpanded: boolean,
|
||||||
|
isPasswordSaved: boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
const defaultState: AppState = {
|
const defaultState: AppState = {
|
||||||
|
@ -66,6 +67,7 @@ const defaultState: AppState = {
|
||||||
searchOptionsExpanded: false,
|
searchOptionsExpanded: false,
|
||||||
currentScroll: 0,
|
currentScroll: 0,
|
||||||
scrollHistory: [0],
|
scrollHistory: [0],
|
||||||
|
isPasswordSaved: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
// @@router comes from react-router
|
// @@router comes from react-router
|
||||||
|
@ -96,6 +98,11 @@ reducers[ACTIONS.DAEMON_READY] = state =>
|
||||||
daemonReady: true,
|
daemonReady: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
reducers[ACTIONS.PASSWORD_SAVED] = (state, action) =>
|
||||||
|
Object.assign({}, state, {
|
||||||
|
isPasswordSaved: action.data,
|
||||||
|
});
|
||||||
|
|
||||||
reducers[ACTIONS.DAEMON_VERSION_MATCH] = state =>
|
reducers[ACTIONS.DAEMON_VERSION_MATCH] = state =>
|
||||||
Object.assign({}, state, {
|
Object.assign({}, state, {
|
||||||
daemonVersionMatched: true,
|
daemonVersionMatched: true,
|
||||||
|
|
|
@ -133,3 +133,8 @@ export const selectScrollStartingPosition = createSelector(
|
||||||
selectState,
|
selectState,
|
||||||
state => state.currentScroll
|
state => state.currentScroll
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const selectIsPasswordSaved = createSelector(
|
||||||
|
selectState,
|
||||||
|
state => state.isPasswordSaved
|
||||||
|
);
|
||||||
|
|
10
src/ui/util/saved-passwords.js
Normal file
10
src/ui/util/saved-passwords.js
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
import keytar from 'keytar';
|
||||||
|
import { AUTH_ORG } from 'constants/keychain';
|
||||||
|
|
||||||
|
export const setSavedPassword = (key, value) => {
|
||||||
|
keytar.setPassword(AUTH_ORG, key, value);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getSavedPassword = key => keytar.getPassword(AUTH_ORG, key).then(p => p);
|
||||||
|
|
||||||
|
export const deleteSavedPassword = key => keytar.deletePassword(AUTH_ORG, key).catch(e => console.log(e));
|
|
@ -81,6 +81,7 @@ let baseConfig = {
|
||||||
loader: 'raw-loader',
|
loader: 'raw-loader',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{ test: /\.node$/, loader: 'node-loader' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
// Allows imports for all directories inside '/ui'
|
// Allows imports for all directories inside '/ui'
|
||||||
|
|
Loading…
Add table
Reference in a new issue