security settings: dynamic Set/Change labels, delete password shortcut

This commit is contained in:
myxmaster
2026-02-17 19:15:05 +01:00
parent d2ba507f4a
commit 6b5b92a22e
6 changed files with 171 additions and 50 deletions
+9 -4
View File
@@ -1042,16 +1042,19 @@
"views.Settings.Privacy.clipboard": "Read clipboard",
"views.Settings.Privacy.clipboard.explainer": "If enabled, Zeus will read values copied to your clipboard and prompt you if they can be used in the app.",
"views.Settings.Privacy.enableMempoolRates": "Enable Mempool.space fee suggestions",
"views.Settings.SetPassword.title": "Set / Change Password",
"views.Settings.SetPassword.title": "Set Password",
"views.Settings.ChangePassword.title": "Change Password",
"views.Settings.SetPassword.save": "Save",
"views.Settings.SetPassword.noMatch": "Passwords do not match",
"views.Settings.SetPassword.invalid": "Password and duress password cannot be the same",
"views.Settings.SetPassword.empty": "Password can not be empty",
"views.Settings.SetPassword.deletePassword": "Delete Password",
"views.Settings.SetDuressPassword.title": "Set / Change Duress Password",
"views.Settings.SetDuressPassword.title": "Set Duress Password",
"views.Settings.ChangeDuressPassword.title": "Change Duress Password",
"views.Settings.SetDuressPassword.deletePassword": "Delete Duress Password",
"views.Settings.SetDuressPassword.duressPasswordExplanation": "Once set, you can enter your duress password on the login screen to delete all of your wallet configurations.",
"views.Settings.SetPin.title": "Set / Change PIN",
"views.Settings.SetPin.title": "Set PIN",
"views.Settings.ChangePin.title": "Change PIN",
"views.Settings.Security.BiometryRequiresPinOrPassword": "To enable biometric authentication, you need to set up a PIN or Password first as a backup method.",
"views.Settings.Security.FaceID.title": "FaceID",
"views.Settings.Security.TouchID.title": "TouchID",
@@ -1062,9 +1065,11 @@
"views.Settings.SetPin.noMatch": "PINs do not match. Please resubmit.",
"views.Settings.SetPin.invalid": "PIN and Duress PIN cannot be equal.",
"views.Settings.SetPin.createPin": "Create your PIN",
"views.Settings.SetPin.newPin": "Enter your new PIN",
"views.Settings.SetPin.confirmPin": "Confirm your PIN",
"views.Settings.SetPin.scramblePin": "The order of numbers on the PIN Pad is randomized to prevent against attacks",
"views.Settings.SetDuressPin.title": "Set / Change Duress PIN",
"views.Settings.SetDuressPin.title": "Set Duress PIN",
"views.Settings.ChangeDuressPin.title": "Change Duress PIN",
"views.Settings.SetDuressPin.createDuressPin": "Create your Duress PIN",
"views.Settings.SetDuressPin.duressPinExplanation": "Once set, you can enter your duress PIN on the PIN login screen to delete all of your wallet configurations.",
"views.Settings.SetDuressPin.confirmDuressPin": "Confirm your Duress PIN",
+71 -4
View File
@@ -36,6 +36,8 @@ interface LockscreenProps {
modifySecurityScreen: string;
deletePin: boolean;
deleteDuressPin: boolean;
deletePassword: boolean;
deleteDuressPassword: boolean;
pendingNavigation?: { screen: string; params?: any };
shareIntentData?: { qrData?: string; base64Image?: string };
}
@@ -54,6 +56,8 @@ interface LockscreenState {
modifySecurityScreen: string;
deletePin: boolean;
deleteDuressPin: boolean;
deletePassword: boolean;
deleteDuressPassword: boolean;
authenticationAttempts: number;
}
@@ -81,6 +85,8 @@ export default class Lockscreen extends React.Component<
modifySecurityScreen: '',
deletePin: false,
deleteDuressPin: false,
deletePassword: false,
deleteDuressPassword: false,
authenticationAttempts: 0
};
}
@@ -126,6 +132,8 @@ export default class Lockscreen extends React.Component<
modifySecurityScreen,
deletePin,
deleteDuressPin,
deletePassword,
deleteDuressPassword,
pendingNavigation
} = route.params ?? {};
@@ -138,7 +146,9 @@ export default class Lockscreen extends React.Component<
SettingsStore.posStatus === 'active' &&
!pendingNavigation &&
!deletePin &&
!deleteDuressPin
!deleteDuressPin &&
!deletePassword &&
!deleteDuressPassword
) {
// If POS is enabled and active, proceed without authentication
SettingsStore.setLoginStatus(true);
@@ -152,6 +162,8 @@ export default class Lockscreen extends React.Component<
isBiometryConfigured &&
!deletePin &&
!deleteDuressPin &&
!deletePassword &&
!deleteDuressPassword &&
!modifySecurityScreen
) {
const isVerified = await verifyBiometry(
@@ -191,6 +203,14 @@ export default class Lockscreen extends React.Component<
this.setState({
deleteDuressPin
});
} else if (deletePassword) {
this.setState({
deletePassword
});
} else if (deleteDuressPassword) {
this.setState({
deleteDuressPassword
});
}
if (settings && settings.passphrase) {
@@ -244,7 +264,9 @@ export default class Lockscreen extends React.Component<
duressPin,
modifySecurityScreen,
deletePin,
deleteDuressPin
deleteDuressPin,
deletePassword,
deleteDuressPassword
} = this.state;
const { updateSettings, getSettings, setPosStatus } = SettingsStore;
@@ -263,9 +285,15 @@ export default class Lockscreen extends React.Component<
this.resetAuthenticationAttempts();
navigation.popTo(modifySecurityScreen);
return;
} else if (deletePassword) {
this.deletePassword();
return;
} else if (deletePin) {
this.deletePin();
return;
} else if (deleteDuressPassword) {
this.deleteDuressPassword();
return;
} else if (deleteDuressPin) {
this.deleteDuressPin();
return;
@@ -361,6 +389,34 @@ export default class Lockscreen extends React.Component<
});
};
deletePassword = () => {
const { SettingsStore, navigation } = this.props;
const { updateSettings } = SettingsStore;
// duress passphrase is also deleted when passphrase is deleted
// biometry is also disabled when passphrase is deleted
updateSettings({
passphrase: '',
duressPassphrase: '',
authenticationAttempts: 0,
isBiometryEnabled: false
}).then(() => {
navigation.popTo('Security');
});
};
deleteDuressPassword = () => {
const { SettingsStore, navigation } = this.props;
const { updateSettings } = SettingsStore;
updateSettings({
duressPassphrase: '',
authenticationAttempts: 0
}).then(() => {
navigation.popTo('Security');
});
};
deletePin = () => {
const { SettingsStore, navigation } = this.props;
const { updateSettings } = SettingsStore;
@@ -457,7 +513,9 @@ export default class Lockscreen extends React.Component<
error,
modifySecurityScreen,
deletePin,
deleteDuressPin
deleteDuressPin,
deletePassword,
deleteDuressPassword
} = this.state;
return (
@@ -465,6 +523,8 @@ export default class Lockscreen extends React.Component<
{(!!modifySecurityScreen ||
deletePin ||
deleteDuressPin ||
deletePassword ||
deleteDuressPassword ||
pendingNavigation) && (
<Header leftComponent="Back" navigation={navigation} />
)}
@@ -525,10 +585,17 @@ export default class Lockscreen extends React.Component<
</View>
<View style={styles.button}>
<Button
title={localeString('views.Lockscreen.login')}
title={localeString(
deletePassword
? 'views.Settings.SetPassword.deletePassword'
: deleteDuressPassword
? 'views.Settings.SetDuressPassword.deletePassword'
: 'views.Lockscreen.login'
)}
onPress={() => this.onAttemptLogIn()}
containerStyle={{ width: 300 }}
adaptiveWidth
warning={deletePassword || deleteDuressPassword}
/>
</View>
</View>
+80 -39
View File
@@ -33,33 +33,6 @@ interface SecurityState {
isBiometryEnabled: boolean | undefined;
}
const possibleSecurityItems = [
{
translateKey: 'views.Settings.SetPassword.title',
screen: 'SetPassword'
},
{
translateKey: 'views.Settings.SetDuressPassword.title',
screen: 'SetDuressPassword'
},
{
translateKey: 'views.Settings.SetPin.title',
screen: 'SetPin'
},
{
translateKey: 'views.Settings.Security.deletePIN',
action: 'DeletePin'
},
{
translateKey: 'views.Settings.SetDuressPin.title',
screen: 'SetDuressPin'
},
{
translateKey: 'views.Settings.Security.deleteDuressPIN',
action: 'DeleteDuressPin'
}
];
@inject('SettingsStore', 'ModalStore')
@observer
export default class Security extends React.Component<
@@ -117,33 +90,75 @@ export default class Security extends React.Component<
// Three cases:
// 1) If no passphrase or pin is set, allow user to set passphrase or pin
// 2) If passphrase is set, allow user to set passphrase or duress passphrase
// 3) If pin is set, allow user to set pin or duress pin
// 2) If passphrase is set, allow user to change passphrase or set/change duress passphrase
// 3) If pin is set, allow user to change pin, delete pin, set/change duress pin
if (!settings.passphrase && !settings.pin) {
this.setState({
displaySecurityItems: [
possibleSecurityItems[0],
possibleSecurityItems[2]
{
translateKey: 'views.Settings.SetPassword.title',
screen: 'SetPassword'
},
{
translateKey: 'views.Settings.SetPin.title',
screen: 'SetPin'
}
]
});
} else if (settings.passphrase) {
this.setState({
displaySecurityItems: [
possibleSecurityItems[0],
possibleSecurityItems[1]
{
translateKey: 'views.Settings.ChangePassword.title',
screen: 'SetPassword'
},
{
translateKey:
'views.Settings.SetPassword.deletePassword',
action: 'DeletePassword'
},
{
translateKey: settings.duressPassphrase
? 'views.Settings.ChangeDuressPassword.title'
: 'views.Settings.SetDuressPassword.title',
screen: 'SetDuressPassword'
},
...(settings.duressPassphrase
? [
{
translateKey:
'views.Settings.SetDuressPassword.deletePassword',
action: 'DeleteDuressPassword'
}
]
: [])
]
});
} else if (settings.pin) {
const minPinItems = [
possibleSecurityItems[2],
possibleSecurityItems[3],
possibleSecurityItems[4]
const items: Array<any> = [
{
translateKey: 'views.Settings.ChangePin.title',
screen: 'SetPin'
},
{
translateKey: 'views.Settings.Security.deletePIN',
action: 'DeletePin'
},
{
translateKey: settings.duressPin
? 'views.Settings.ChangeDuressPin.title'
: 'views.Settings.SetDuressPin.title',
screen: 'SetDuressPin'
}
];
if (settings.duressPin) {
minPinItems.push(possibleSecurityItems[5]);
items.push({
translateKey: 'views.Settings.Security.deleteDuressPIN',
action: 'DeleteDuressPin'
});
}
this.setState({
displaySecurityItems: minPinItems
displaySecurityItems: items
});
}
@@ -235,6 +250,32 @@ export default class Security extends React.Component<
navigation.navigate('Lockscreen', {
deletePin: true
});
} else if (item.action === 'DeletePassword' && isBiometryEnabled) {
ModalStore.toggleInfoModal({
text: [
localeString(
'views.Settings.Security.biometricsWillBeDisabled'
),
localeString('general.continueQuestion')
],
buttons: [
{
title: localeString('general.ok'),
callback: () =>
navigation.navigate('Lockscreen', {
deletePassword: true
})
}
]
});
} else if (item.action === 'DeletePassword') {
navigation.navigate('Lockscreen', {
deletePassword: true
});
} else if (item.action === 'DeleteDuressPassword') {
navigation.navigate('Lockscreen', {
deleteDuressPassword: true
});
} else if (item.action === 'DeleteDuressPin') {
navigation.navigate('Lockscreen', {
deleteDuressPin: true
+3 -1
View File
@@ -128,7 +128,9 @@ export default class SetDuressPassphrase extends React.Component<
leftComponent="Back"
centerComponent={{
text: localeString(
'views.Settings.SetDuressPassword.title'
savedDuressPassphrase
? 'views.Settings.ChangeDuressPassword.title'
: 'views.Settings.SetDuressPassword.title'
),
style: {
color: themeColor('text'),
+5 -1
View File
@@ -144,7 +144,11 @@ export default class SetPassphrase extends React.Component<
<Header
leftComponent="Back"
centerComponent={{
text: localeString('views.Settings.SetPassword.title'),
text: localeString(
savedPassphrase
? 'views.Settings.ChangePassword.title'
: 'views.Settings.SetPassword.title'
),
style: {
color: themeColor('text'),
fontFamily: 'PPNeueMontreal-Book'
+3 -1
View File
@@ -143,7 +143,9 @@ export default class SetPin extends React.Component<SetPinProps, SetPinState> {
}}
>
{localeString(
'views.Settings.SetPin.createPin'
settings.pin
? 'views.Settings.SetPin.newPin'
: 'views.Settings.SetPin.createPin'
)}
</Text>
{(settings.scramblePin ||