feat: change vault password

This commit is contained in:
ammarahm-ed
2020-11-25 11:46:44 +05:00
parent 110ff7d9b5
commit 8c73fa24b7
5 changed files with 200 additions and 85 deletions

View File

@@ -18,6 +18,7 @@ const BaseDialog = ({
onShow,
animation = 'fade',
premium,
statusBarTranslucent=true
}) => {
const [state, dispatch] = useTracked();
const scaleValue = new Animated.Value(1);
@@ -27,7 +28,7 @@ const BaseDialog = ({
visible={visible}
transparent={true}
animated
statusBarTranslucent
statusBarTranslucent={statusBarTranslucent}
onShow={() => {
if (onShow) {
onShow();

View File

@@ -1,5 +1,6 @@
import React from 'react';
import {StyleSheet, View} from 'react-native';
import {ActivityIndicator, StyleSheet, View} from 'react-native';
import {useTracked} from '../../provider';
import {SIZE} from '../../utils/SizeUtils';
import {Button} from '../Button';
@@ -8,28 +9,40 @@ const DialogButtons = ({
onPressNegative,
positiveTitle,
negativeTitle = 'Cancel',
loading,
}) => {
const [state] = useTracked();
const {colors} = state;
return (
<View style={styles.container}>
<Button
onPress={onPressNegative}
fontSize={SIZE.md}
type="gray"
width="25%"
title={negativeTitle}
/>
{onPressPositive && (
{loading ? (
<ActivityIndicator color={colors.accent} size={SIZE.lg} />
) : <View/>}
<View
style={{
flexDirection: 'row',
alignItems: 'center',
}}>
<Button
onPress={onPressPositive}
onPress={onPressNegative}
fontSize={SIZE.md}
style={{
marginLeft:10
}}
width="25%"
type="transparent"
title={positiveTitle}
type="gray"
title={negativeTitle}
/>
)}
{onPressPositive && (
<Button
onPress={onPressPositive}
fontSize={SIZE.md}
style={{
marginLeft: 10,
}}
type="transparent"
title={positiveTitle}
/>
)}
</View>
</View>
);
};
@@ -38,7 +51,7 @@ export default DialogButtons;
const styles = StyleSheet.create({
container: {
justifyContent: 'flex-end',
justifyContent: 'space-between',
alignItems: 'center',
flexDirection: 'row',
marginTop: 20,

View File

@@ -33,13 +33,14 @@ import Paragraph from '../Typography/Paragraph';
const passInputRef = createRef();
const confirmPassRef = createRef();
const changePassInputRef = createRef();
export class VaultDialog extends Component {
constructor(props) {
super(props);
this.state = {
visible: false,
wrongPassword: false,
loading: false,
note: {},
vault: false,
locked: true,
@@ -52,9 +53,11 @@ export class VaultDialog extends Component {
biometricUnlock: false,
isBiometryAvailable: false,
fingerprintAccess: false,
changePassword: false,
};
this.password = null;
this.confirmPassword = null;
this.newPassword = null;
}
componentDidMount() {
@@ -94,6 +97,7 @@ export class VaultDialog extends Component {
isBiometryAvailable: available,
biometricUnlock: fingerprint,
fingerprintAccess: data.fingerprintAccess,
changePassword: data.changePassword,
});
if (fingerprint && this.state.novault && !this.state.fingerprintAccess) {
await this._onPressFingerprintAuth();
@@ -101,6 +105,10 @@ export class VaultDialog extends Component {
};
close = () => {
if (this.state.loading) {
ToastEvent.show('Please wait and do not close the app.', 'success');
return;
}
updateEvent({type: Actions.NOTES});
this.password = null;
@@ -119,8 +127,9 @@ export class VaultDialog extends Component {
};
onPress = async () => {
if (this.state.loading) return;
if (!this.state.novault) {
if (this.password.length < 3) {
if (this.password && this.password.length < 3) {
ToastEvent.show('Password too short', 'error', 'local');
return;
@@ -134,6 +143,35 @@ export class VaultDialog extends Component {
}
this._createVault();
} else if (this.state.changePassword) {
if (this.newPassword && this.newPassword.length < 3) {
ToastEvent.show('New password too short', 'error', 'local');
return;
}
this.setState({
loading: true,
});
db.vault
.changePassword(this.password, this.newPassword)
.then((result) => {
this.setState({
loading: false,
});
if (this.state.biometricUnlock) {
this._enrollFingerprint(this.newPassword);
}
ToastEvent.show('Vault password changed', 'success');
this.close();
})
.catch((e) => {
this.setState({
loading: false,
});
if (e === db.vault.ERRORS.wrongPassword) {
ToastEvent.show('Current password incorrect.', 'error', 'local');
}
});
} else if (this.state.locked) {
if (!this.password || this.password.trim() === 0) {
ToastEvent.show('Password is invalid', 'error', 'local');
@@ -159,7 +197,7 @@ export class VaultDialog extends Component {
});
}
} else if (this.state.fingerprintEnroll) {
this._enrollFingerprint();
this._enrollFingerprint(this.password);
}
};
@@ -214,20 +252,13 @@ export class VaultDialog extends Component {
ToastEvent.show('Note deleted', 'success', 'local');
}
async _enrollFingerprint() {
async _enrollFingerprint(password) {
try {
await Keychain.setInternetCredentials(
'nn_vault',
'nn_vault',
this.password,
{
accessControl:
Keychain.ACCESS_CONTROL.BIOMETRY_ANY_OR_DEVICE_PASSCODE,
authenticationPrompt: {cancel: null},
accessible:
Keychain.AUTHENTICATION_TYPE.DEVICE_PASSCODE_OR_BIOMETRICS,
},
);
await Keychain.setInternetCredentials('nn_vault', 'nn_vault', password, {
accessControl: Keychain.ACCESS_CONTROL.BIOMETRY_ANY_OR_DEVICE_PASSCODE,
authenticationPrompt: {cancel: null},
accessible: Keychain.AUTHENTICATION_TYPE.DEVICE_PASSCODE_OR_BIOMETRICS,
});
} catch (e) {
this._takeErrorAction(e);
}
@@ -320,6 +351,13 @@ export class VaultDialog extends Component {
locked,
permanant,
biometricUnlock,
deleteNote,
share,
goToEditor,
fingerprintAccess,
changePassword,
copyNote,
loading,
} = this.state;
if (!visible) return null;
@@ -328,6 +366,7 @@ export class VaultDialog extends Component {
onShow={() => {
passInputRef.current?.focus();
}}
statusBarTranslucent={false}
onRequestClose={this.close}
visible={true}>
<View
@@ -343,14 +382,16 @@ export class VaultDialog extends Component {
title={
!novault
? 'Create Vault'
: this.state.fingerprintAccess
: fingerprintAccess
? 'Fingerprint Access'
: changePassword
? 'Change Vault Password'
: note.locked
? this.state.deleteNote
? deleteNote
? 'Delete note'
: this.state.share
: share
? 'Share note'
: this.state.goToEditor
: goToEditor
? 'Unlock note'
: 'Unlock note'
: 'Lock note'
@@ -358,16 +399,18 @@ export class VaultDialog extends Component {
paragraph={
!novault
? 'Set a password to create vault'
: this.state.fingerprintAccess
: fingerprintAccess
? 'Enter vault password to enable access to the vault with fingerprint'
: changePassword
? 'Setup a new password for the vault.'
: permanant
? 'Enter password to remove note from vault.'
: note.locked
? this.state.deleteNote
? deleteNote
? 'Unlock note to delete it.'
: this.state.share
: share
? 'Unlock note to share it.'
: this.state.goToEditor
: goToEditor
? 'Unlock note to open it in editor'
: 'Enter vault password to unlock note.'
: 'Enter vault password to lock note.'
@@ -380,10 +423,13 @@ export class VaultDialog extends Component {
{note.locked ||
locked ||
permanant ||
this.state.fingerprintAccess ? (
fingerprintAccess ||
changePassword ? (
<>
<TextInput
ref={passInputRef}
editable={!loading}
autoCapitalize="none"
style={{
padding: pv - 5,
borderBottomWidth: 1.5,
@@ -393,7 +439,6 @@ export class VaultDialog extends Component {
? colors.accent
: colors.nav,
paddingHorizontal: ph,
borderRadius: 5,
marginTop: 10,
fontSize: SIZE.sm,
fontFamily: WEIGHT.regular,
@@ -407,11 +452,14 @@ export class VaultDialog extends Component {
});
}}
secureTextEntry
placeholder="Password"
placeholder={changePassword ? 'Current Password' : 'Password'}
placeholderTextColor={colors.icon}
/>
<Seperator />
{!this.state.biometricUnlock || !novault ? null : (
{!this.state.biometricUnlock ||
!novault ||
changePassword ? null : (
<Button
onPress={this._onPressFingerprintAuth}
width="100%"
@@ -426,10 +474,46 @@ export class VaultDialog extends Component {
</>
) : null}
{changePassword ? (
<>
<TextInput
ref={changePassInputRef}
editable={!loading}
autoCapitalize="none"
style={{
padding: pv - 5,
borderBottomWidth: 1.5,
borderColor: wrongPassword
? colors.errorText
: this.state.focusIndex === 0
? colors.accent
: colors.nav,
paddingHorizontal: ph,
marginTop: 10,
fontSize: SIZE.sm,
fontFamily: WEIGHT.regular,
}}
onChangeText={(value) => {
this.newPassword = value;
}}
onFocus={() => {
this.setState({
focusIndex: 0,
});
}}
secureTextEntry
placeholder={'New Password'}
placeholderTextColor={colors.icon}
/>
<Seperator />
</>
) : null}
{!novault ? (
<View>
<TextInput
ref={passInputRef}
autoCapitalize="none"
style={{
padding: pv - 5,
borderBottomWidth: 1.5,
@@ -439,7 +523,6 @@ export class VaultDialog extends Component {
? colors.accent
: colors.nav,
paddingHorizontal: ph,
borderRadius: 5,
fontSize: SIZE.sm,
fontFamily: WEIGHT.regular,
}}
@@ -458,6 +541,7 @@ export class VaultDialog extends Component {
<TextInput
ref={confirmPassRef}
autoCapitalize="none"
style={{
padding: pv - 5,
borderBottomWidth: 1.5,
@@ -467,7 +551,6 @@ export class VaultDialog extends Component {
? colors.accent
: colors.nav,
paddingHorizontal: ph,
borderRadius: 5,
fontSize: SIZE.sm,
fontFamily: WEIGHT.regular,
marginTop: 10,
@@ -498,7 +581,7 @@ export class VaultDialog extends Component {
{this.state.isBiometryAvailable &&
!this.state.fingerprintAccess &&
(!this.state.biometricUnlock || !novault) ? (
((!this.state.biometricUnlock && !changePassword) || !novault) ? (
<TouchableOpacity
onPress={() => {
this.setState({
@@ -540,15 +623,18 @@ export class VaultDialog extends Component {
<DialogButtons
onPressNegative={this.close}
onPressPositive={this.onPress}
loading={loading}
positiveTitle={
this.state.fingerprintAccess
fingerprintAccess
? 'Enable'
: changePassword
? 'Change'
: note.locked
? this.state.deleteNote
? deleteNote
? 'Delete'
: this.state.share
: share
? 'Share '
: this.state.goToEditor
: goToEditor
? 'Open'
: 'Unlock'
: !note.id

View File

@@ -19,13 +19,14 @@ export const eSendEvent = (eventName, data) => {
* @typedef {Object} vaultType
* @property {Object} item
* @property {boolean} novault
* @property {Object} locked
* @property {Object} permanant
* @property {Object} goToEditor
* @property {Object} share
* @property {Object} deleteNote
* @property {Object} fingerprintAccess
* @property {Object} copyNote
* @property {boolean} locked
* @property {boolean} permanant
* @property {boolean} goToEditor
* @property {boolean} share
* @property {boolean} deleteNote
* @property {boolean} fingerprintAccess
* @property {boolean} changePassword
* @property {boolean} copyNote
* @param {vaultType} data
*/

View File

@@ -783,38 +783,52 @@ export const Settings = ({navigation}) => {
/>
{vaultStatus.exists ? (
vaultStatus.isBiometryAvailable ? (
<>
{vaultStatus.isBiometryAvailable ? (
<CustomButton
key="fingerprintVaultUnlock"
title="Unlock vault with Fingerprint"
tagline={
!vaultStatus.biometryEnrolled
? 'Enable access to the vault with fingerprint.'
: 'You can access the vault with fingerprint.'
}
onPress={() => {
openVault({
item: {},
fingerprintAccess: true,
novault: true,
});
}}
maxWidth="90%"
customComponent={
<Icon
size={SIZE.xl}
color={
vaultStatus.biometryEnrolled ? colors.accent : colors.icon
}
name={
vaultStatus.biometryEnrolled
? 'toggle-switch'
: 'toggle-switch-off'
}
/>
}
/>
) : null}
<CustomButton
key="fingerprintVaultUnlock"
title="Unlock vault with Fingerprint"
tagline={
!vaultStatus.biometryEnrolled
? 'Enable access to the vault with fingerprint.'
: 'You can access the vault with fingerprint.'
}
key="changeVaultPassword"
title="Change Vault Password"
tagline="Setup a new password for the vault"
onPress={() => {
openVault({
item: {},
fingerprintAccess: true,
changePassword: true,
novault: true,
});
}}
maxWidth="90%"
customComponent={
<Icon
size={SIZE.xl}
color={
vaultStatus.biometryEnrolled ? colors.accent : colors.icon
}
name={
vaultStatus.biometryEnrolled
? 'toggle-switch'
: 'toggle-switch-off'
}
/>
}
/>
) : null
</>
) : (
<CustomButton
key="createVault"