add email to syncPassword component and more sync cleanup

This commit is contained in:
Sean Yesmunt 2019-10-24 11:48:58 -04:00
parent 8f42280969
commit 6b61a544bc
9 changed files with 22 additions and 530 deletions

View file

@ -6,15 +6,13 @@ import {
doRewardList,
doFetchRewardedContent,
doFetchAccessToken,
selectAccessToken,
selectGetSyncErrorMessage,
selectUploadCount,
} from 'lbryinc';
import { doFetchTransactions, doFetchChannelListMine, selectBalance } from 'lbry-redux';
import { doFetchTransactions, doFetchChannelListMine } from 'lbry-redux';
import { makeSelectClientSetting, selectThemePath } from 'redux/selectors/settings';
import { selectIsUpgradeAvailable, selectAutoUpdateDownloaded } from 'redux/selectors/app';
import { doDownloadUpgradeRequested, doSignIn, doSyncWithPreferences } from 'redux/actions/app';
import { doSetClientSetting } from 'redux/actions/settings';
import App from './view';
const select = state => ({
@ -23,10 +21,8 @@ const select = state => ({
language: makeSelectClientSetting(SETTINGS.LANGUAGE)(state),
autoUpdateDownloaded: selectAutoUpdateDownloaded(state),
isUpgradeAvailable: selectIsUpgradeAvailable(state),
balance: selectBalance(state),
syncEnabled: makeSelectClientSetting(SETTINGS.ENABLE_SYNC)(state),
syncError: selectGetSyncErrorMessage(state),
accessToken: selectAccessToken(state),
uploadCount: selectUploadCount(state),
});
@ -39,7 +35,6 @@ const perform = dispatch => ({
signIn: () => dispatch(doSignIn()),
requestDownloadUpgrade: () => dispatch(doDownloadUpgradeRequested()),
checkSync: () => dispatch(doSyncWithPreferences()),
setSyncEnabled: value => dispatch(doSetClientSetting(SETTINGS.ENABLE_SYNC, value)),
});
export default hot(

View file

@ -1,6 +1,5 @@
// @flow
import * as ICONS from 'constants/icons';
import * as ACTIONS from 'constants/action_types';
import * as PAGES from 'constants/pages';
import React, { useEffect, useRef, useState } from 'react';
import classnames from 'classnames';
@ -16,8 +15,6 @@ import FileViewer from 'component/fileViewer';
import { withRouter } from 'react-router';
import usePrevious from 'effects/use-previous';
import Button from 'component/button';
import usePersistedState from 'effects/use-persisted-state';
import { Lbryio } from 'lbryinc';
export const MAIN_WRAPPER_CLASS = 'main-wrapper';
// @if TARGET='app'
@ -45,7 +42,6 @@ type Props = {
isUpgradeAvailable: boolean,
autoUpdateDownloaded: boolean,
checkSync: () => void,
setSyncEnabled: boolean => void,
syncEnabled: boolean,
uploadCount: number,
balance: ?number,
@ -66,12 +62,9 @@ function App(props: Props) {
autoUpdateDownloaded,
isUpgradeAvailable,
requestDownloadUpgrade,
setSyncEnabled,
syncEnabled,
checkSync,
uploadCount,
balance,
accessToken,
history,
syncError,
} = props;
@ -79,7 +72,6 @@ function App(props: Props) {
const appRef = useRef();
const isEnhancedLayout = useKonamiListener();
const [hasSignedIn, setHasSignedIn] = useState(false);
const [hasDeterminedIfNewUser, setHasDeterminedIfNewUser] = usePersistedState('is-new-user', false);
const userId = user && user.id;
const hasVerifiedEmail = user && user.has_verified_email;
const isRewardApproved = user && user.is_reward_approved;
@ -95,41 +87,6 @@ function App(props: Props) {
uri = newpath + hash;
} catch (e) {}
// This should not be needed and will be removed after 37 is released
// We should just be able to default the enableSync setting to true, but we don't want
// to automatically opt-in existing users. Only users that go through the new sign in flow
// should be automatically opted-in (they choose to uncheck the option and turn off sync still)
useEffect(() => {
if (balance === undefined || accessToken === undefined || hasDeterminedIfNewUser) {
return;
}
// Manually call subscription/list once because I was dumb and wasn't persisting it in redux
Lbryio.call('subscription', 'list').then(response => {
if (response && response.length) {
const subscriptions = response.map(value => {
const { channel_name: channelName, claim_id: claimId } = value;
return {
channelName,
uri: buildURI({ channelName, channelClaimId: claimId }),
};
});
window.store.dispatch({
type: ACTIONS.FETCH_SUBSCRIPTIONS_SUCCESS,
data: subscriptions,
});
}
// Yeah... this isn't the best check, but it works for now
const newUser = balance === 0;
if (newUser) {
setSyncEnabled(true);
}
setHasDeterminedIfNewUser(true);
});
}, [balance, accessToken, hasDeterminedIfNewUser, setHasDeterminedIfNewUser]);
useEffect(() => {
if (!uploadCount) return;
const handleBeforeUnload = event => {
@ -187,7 +144,7 @@ function App(props: Props) {
}, [hasVerifiedEmail, signIn, hasSignedIn]);
useEffect(() => {
if (hasVerifiedEmail && syncEnabled && hasDeterminedIfNewUser) {
if (hasVerifiedEmail && syncEnabled) {
checkSync();
let syncInterval = setInterval(() => {
@ -198,7 +155,7 @@ function App(props: Props) {
clearInterval(syncInterval);
};
}
}, [hasVerifiedEmail, syncEnabled, checkSync, hasDeterminedIfNewUser]);
}, [hasVerifiedEmail, syncEnabled, checkSync]);
useEffect(() => {
if (syncError) {

View file

@ -1,10 +1,11 @@
import { connect } from 'react-redux';
import { doGetSync, selectGetSyncIsPending } from 'lbryinc';
import { doGetSync, selectGetSyncIsPending, selectUserEmail } from 'lbryinc';
import { doSetClientSetting } from 'redux/actions/settings';
import SyncPassword from './view';
const select = state => ({
getSyncIsPending: selectGetSyncIsPending(state),
email: selectUserEmail(state),
});
const perform = dispatch => ({

View file

@ -9,10 +9,11 @@ import usePersistedState from 'effects/use-persisted-state';
type Props = {
getSync: (?string) => void,
getSyncIsPending: boolean,
email: string,
};
function SyncPassword(props: Props) {
const { getSync, getSyncIsPending } = props;
const { getSync, getSyncIsPending, email } = props;
const [password, setPassword] = React.useState('');
const [rememberPassword, setRememberPassword] = usePersistedState(true);
@ -25,12 +26,14 @@ function SyncPassword(props: Props) {
<Form onSubmit={handleSubmit}>
<Card
title={__('Enter Your LBRY Password')}
subtitle={__('You set your wallet password when you previously installed LBRY.')}
subtitle={__(
'You set your wallet password when you previously installed LBRY. This may have been on different device.'
)}
actions={
<div>
<FormField
type="password"
label={__('Password')}
label={__('Password for %email%', { email })}
value={password}
onChange={e => setPassword(e.target.value)}
/>

View file

@ -1,61 +0,0 @@
import { connect } from 'react-redux';
import {
doWalletStatus,
doWalletEncrypt,
doWalletDecrypt,
selectWalletEncryptSucceeded,
selectWalletEncryptPending,
selectWalletEncryptResult,
selectWalletIsEncrypted,
selectHasTransactions,
} from 'lbry-redux';
import WalletSecurityAndSync from './view';
import {
doCheckSync,
doGetSync,
doSetDefaultAccount,
doSyncApply,
selectHasSyncedWallet,
selectGetSyncIsPending,
selectSetSyncIsPending,
selectSyncApplyIsPending,
selectSyncApplyErrorMessage,
selectSyncData,
selectSyncHash,
selectHashChanged,
selectUser,
} from 'lbryinc';
import { doSetClientSetting } from 'redux/actions/settings';
const select = state => ({
walletEncryptSucceeded: selectWalletEncryptSucceeded(state),
walletEncryptPending: selectWalletEncryptPending(state),
walletEncryptResult: selectWalletEncryptResult(state),
walletEncrypted: selectWalletIsEncrypted(state),
walletHasTransactions: selectHasTransactions(state),
user: selectUser(state),
hasSyncedWallet: selectHasSyncedWallet(state),
getSyncIsPending: selectGetSyncIsPending(state),
setSyncIsPending: selectSetSyncIsPending(state),
syncApplyIsPending: selectSyncApplyIsPending(state),
syncApplyErrorMessage: selectSyncApplyErrorMessage(state),
syncData: selectSyncData(state),
syncHash: selectSyncHash(state),
hashChanged: selectHashChanged(state),
});
const perform = dispatch => ({
encryptWallet: password => dispatch(doWalletEncrypt(password)),
decryptWallet: () => dispatch(doWalletDecrypt()),
updateWalletStatus: () => dispatch(doWalletStatus()),
syncApply: (hash, data, password) => dispatch(doSyncApply(hash, data, password)),
getSync: password => dispatch(doGetSync(password, true)),
checkSync: () => dispatch(doCheckSync()),
setDefaultAccount: () => dispatch(doSetDefaultAccount()),
setClientSetting: (key, value) => dispatch(doSetClientSetting(key, value)),
});
export default connect(
select,
perform
)(WalletSecurityAndSync);

View file

@ -1,405 +0,0 @@
export default () => null;
// // @flow
// import React, { useState } 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, deleteAuthToken } from 'util/saved-passwords';
// 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,
// advancedMode: boolean,
// showPasswordFields: boolean,
// };
// function WalletSecurityAndSync(props: Props) {
// const {
// // walletEncryptSucceeded,
// // walletEncryptPending,
// // walletDecryptSucceeded,
// // walletDecryptPending,
// // updateWalletStatus,
// walletEncrypted,
// encryptWallet,
// decryptWallet,
// syncEnabled,
// 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,
// advancedMode: false,
// showPasswordFields: false,
// };
// const [componentState, setComponentState] = useState<State>(defaultComponentState);
// const safeToSync = !hasTransactions || !hashChanged;
// // on mount
// // useEffect(() => {
// // checkSync();
// // getSavedPassword().then(p => {
// // if (p) {
// // setComponentState({
// // ...componentState,
// // newPassword: p,
// // newPasswordConfirm: p,
// // showPasswordFields: true,
// // rememberPassword: true,
// // });
// // }
// // });
// // }, []);
// // 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<>) {
// if (componentState.rememberPassword) {
// deleteAuthToken();
// }
// 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<>) {
// if (componentState.enableSync) {
// setComponentState({ ...componentState, enableSync: false, newPassword: '', newPasswordConfirm: '' });
// setComponentState({ ...componentState, enableSync: false, newPassword: '', newPasswordConfirm: '' });
// }
// if (!(walletEncrypted || syncApplyErrorMessage || componentState.advancedMode)) {
// easyApply();
// } else {
// setComponentState({ ...componentState, enableSync: true });
// }
// }
// function onChangeEncrypt(event: SyntheticInputEvent<>) {
// setComponentState({ ...componentState, encryptWallet: event.target.checked });
// }
// async function easyApply() {
// return new Promise((resolve, reject) => {
// return syncApply(syncHash, syncData, componentState.newPassword);
// })
// .then(() => {
// setComponentState({ ...componentState, enableSync: event.target.checked });
// })
// .catch();
// }
// async function apply() {
// setComponentState({ ...componentState, failed: false });
// await checkSync();
// if (componentState.enableSync) {
// await syncApply(syncHash, syncData, componentState.newPassword);
// if (syncApplyErrorMessage) {
// setComponentState({ ...componentState, failed: true });
// }
// }
// if (walletEncrypted) {
// await decryptWallet();
// }
// if (componentState.encryptWallet && !componentState.failed) {
// await encryptWallet(componentState.newPassword)
// .then(() => {})
// .catch(() => {
// setComponentState({ ...componentState, failed: false });
// });
// }
// if (componentState.rememberPassword && !componentState.failed) {
// setSavedPassword(componentState.newPassword);
// }
// }
// return (
// <React.Fragment>
// <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>
// )}
// <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>
// {/* Errors and status */}
// {!componentState.advancedMode && (
// <React.Fragment>
// <p className="card__subtitle">
// {__(`Easy Mode: Sync and go with default security! Don't trust your roommate?`)}{' '}
// <Button
// button="link"
// label={__('Advanced Mode')}
// onClick={() => setComponentState({ ...componentState, advancedMode: !componentState.advancedMode })}
// />
// .
// </p>
// </React.Fragment>
// )}
// {componentState.advancedMode && (
// <React.Fragment>
// <p className="card__subtitle">
// {__('Advanced Mode: Enter a password that matches your other devices LBRY password.')}{' '}
// <Button
// button="link"
// label={__('Easy Mode')}
// onClick={() => setComponentState({ ...componentState, advancedMode: !componentState.advancedMode })}
// />
// .
// </p>
// </React.Fragment>
// )}
// {syncApplyErrorMessage && <div className="card__subtitle--status">{__(syncApplyErrorMessage)}</div>}
// <Form onSubmit={() => apply()}>
// {componentState.advancedMode && (
// <FormField
// type="checkbox"
// name="sync_enabled"
// checked={componentState.enableSync}
// disabled={!isEmailVerified || !safeToSync}
// 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>
// }
// />
// )}
// {!componentState.advancedMode && (
// <Button
// button="primary"
// label={__('Sync my wallet')}
// onClick={() => syncApply(syncHash, syncData, componentState.newPassword)}
// />
// )}
// {(walletEncrypted ||
// syncApplyErrorMessage ||
// componentState.advancedMode ||
// componentState.showPasswordFields) && (
// <React.Fragment>
// <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)}
// value={componentState.newPassword}
// />
// <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)}
// value={componentState.newPasswordConfirm}
// />
// <FormField
// label={__('Remember Password')}
// type="checkbox"
// name="wallet-remember-password"
// onChange={event => onChangeRememberPassword(event)}
// checked={componentState.rememberPassword}
// />
// </React.Fragment>
// )}
// {/* Confirmation */}
// {(walletEncrypted || componentState.advancedMode) && (
// <React.Fragment>
// <FormField
// type="checkbox"
// name="encrypt_enabled"
// checked={componentState.encryptWallet}
// disabled={false}
// onChange={event => onChangeEncrypt(event)}
// label={__('Encrypt Wallet')}
// />
// <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)}
// />
// </React.Fragment>
// )}
// {componentState.failMessage && <div className="error-text">{__(componentState.failMessage)}</div>}
// {(walletEncrypted || componentState.advancedMode || syncApplyErrorMessage) && (
// <Submit
// disabled={!componentState.passwordMatch || (!componentState.enableSync && !componentState.encryptWallet)}
// label={componentState.failMessage ? __('Encrypting Wallet') : __('Apply')}
// />
// )}
// </Form>
// </section>
// {/* Testing stuff and Diagnostics */}
// <section className="card card--section">
// <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('testpass')} />{' '}
// <Button
// button="primary"
// label={__('Getpass test')}
// onClick={() => getSavedPassword().then(p => setComponentState({ ...componentState, newPassword: p }))}
// />{' '}
// <Button button="primary" label={__('Deletepass test')} onClick={() => deleteAuthToken()} />{' '}
// <p>
// password:{' '}
// {componentState.newPassword
// ? componentState.newPassword
// : componentState.newPassword === ''
// ? 'blankString'
// : 'null'}
// </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>
// </React.Fragment>
// );
// }
// export default WalletSecurityAndSync;

View file

@ -72,7 +72,7 @@ Lbryio.setOverride(
{
auth_token: '',
language: 'en',
// app_id: status.installation_id,
app_id: status.installation_id,
},
'post'
).then(response => {

View file

@ -38,7 +38,7 @@ import { doAuthenticate, doGetSync } from 'lbryinc';
import { lbrySettings as config, version as appVersion } from 'package.json';
import { push } from 'connected-react-router';
import analytics from 'analytics';
import { deleteAuthToken, getSavedPassword, getAuthToken } from 'util/saved-passwords';
import { deleteAuthToken, deleteSavedPassword, getSavedPassword, getAuthToken } from 'util/saved-passwords';
// @if TARGET='app'
const { autoUpdater } = remote.require('electron-updater');
@ -475,12 +475,14 @@ export function doSyncWithPreferences() {
}
function failCb() {
dispatch(
doToast({
isError: true,
message: __('Unable to load your saved preferences.'),
})
);
deleteSavedPassword().then(() => {
dispatch(
doToast({
isError: true,
message: __('Unable to load your saved preferences.'),
})
);
});
}
doPreferenceGet('shared', successCb, failCb);

View file

@ -11,7 +11,7 @@ const defaultState = {
// UX
[SETTINGS.NEW_USER_ACKNOWLEDGED]: false,
[SETTINGS.EMAIL_COLLECTION_ACKNOWLEDGED]: false,
[SETTINGS.ENABLE_SYNC]: false,
[SETTINGS.ENABLE_SYNC]: true,
// UI
[SETTINGS.LANGUAGE]: window.localStorage.getItem(SETTINGS.LANGUAGE) || 'en',