wrapped up first pass of sealing wizard

This commit is contained in:
Roland Osborne 2023-08-29 12:04:47 -07:00
parent 8491171b82
commit f4ad6c9a9f
5 changed files with 243 additions and 47 deletions

View File

@ -23,6 +23,8 @@ const LightColors = {
primaryButtonText: '#ffffff', primaryButtonText: '#ffffff',
disabledButton: '#dddddd', disabledButton: '#dddddd',
disabledButtonText: '#aaaaaa', disabledButtonText: '#aaaaaa',
dangerButton: '#ff5555',
dangerButtonText: '#ffffff',
inputBase: '#eeeeee', inputBase: '#eeeeee',
inputPlaceholder: '#888888', inputPlaceholder: '#888888',
inputText: '#444444', inputText: '#444444',
@ -64,6 +66,8 @@ const DarkColors = {
primaryButtonText: '#ffffff', primaryButtonText: '#ffffff',
disabledButton: '#aaaaaa', disabledButton: '#aaaaaa',
disabledButtonText: '#888888', disabledButtonText: '#888888',
dangerButton: '#ff888888',
dangerButtonText: '#ffffff',
inputBase: '#ffffff', inputBase: '#ffffff',
inputPlaceholder: '#888888', inputPlaceholder: '#888888',
inputText: '#444444', inputText: '#444444',
@ -109,6 +113,8 @@ export const Colors = {
primaryButtonText: getColor('primaryButtonText'), primaryButtonText: getColor('primaryButtonText'),
disabledButton: getColor('disabledButton'), disabledButton: getColor('disabledButton'),
disabledButtonText: getColor('disabledButtonText'), disabledButtonText: getColor('disabledButtonText'),
dangerButton: getColor('dangerButton'),
dangerButtonText: getColor('dangerButtonText'),
inputBase: getColor('inputBase'), inputBase: getColor('inputBase'),
inputPlaceholder: getColor('inputPlaceholder'), inputPlaceholder: getColor('inputPlaceholder'),
inputText: getColor('inputText'), inputText: getColor('inputText'),

View File

@ -4,7 +4,7 @@ const Strings = [
{ {
visibleRegistry: 'Visible in Registry', visibleRegistry: 'Visible in Registry',
edit: 'Edit', edit: 'Edit',
enableNotifications: 'Enable Notifications', enableNotifications: 'Push Notifications',
sealedTopics: 'Sealed Topics', sealedTopics: 'Sealed Topics',
colorMode: 'Color Mode', colorMode: 'Color Mode',
hourMode: 'Hour', hourMode: 'Hour',
@ -27,8 +27,8 @@ const Strings = [
monthEnd: 'dd/mm', monthEnd: 'dd/mm',
sealUnset: 'Generate a key to enable end-to-end encrypted topics.', sealUnset: 'Generate a key to enable end-to-end encrypted topics.',
sealUnlocked: 'Disabling the sealing key will remove access from all end-to-end encrypted topics until the key is unlocked again.', sealUnlocked: 'Disabling the sealing key will prevent access to all end-to-end encrypted topics from this device until the key is unlocked again.',
sealLocked: 'Unlock the sealing key to enable end-to-end encrypted topics on this device.', sealLocked: 'Unlock the sealing key to support end-to-end encrypted topics on this device.',
sealDelete: 'Deleting the sealing key will premanently remove access to any existing end-to-end encrypted topics for ALL of your devices.', sealDelete: 'Deleting the sealing key will premanently remove access to any existing end-to-end encrypted topics for ALL of your devices.',
password: 'Password', password: 'Password',
confirmPassword: 'Confirm Password', confirmPassword: 'Confirm Password',
@ -46,11 +46,12 @@ const Strings = [
changePassword: 'Change sealing key password.', changePassword: 'Change sealing key password.',
update: 'Update', update: 'Update',
changeKey: 'Change Key Password', changeKey: 'Change Key Password',
delayMessage: 'Key generation can take several minutes.',
}, },
{ {
visibleRegistry: 'Visible dans le Registre', visibleRegistry: 'Visible dans le Registre',
edit: 'Modifier', edit: 'Modifier',
enableNotifications: 'Activer les Notifications', enableNotifications: 'Notifications Push',
sealedTopics: 'Sujets Sécurisés', sealedTopics: 'Sujets Sécurisés',
colorMode: 'Mode de Couleur', colorMode: 'Mode de Couleur',
hourMode: 'Heure', hourMode: 'Heure',
@ -92,11 +93,12 @@ const Strings = [
changePassword: 'Changez le mot de passe de la clé de sécurité.', changePassword: 'Changez le mot de passe de la clé de sécurité.',
update: 'Mise à jour', update: 'Mise à jour',
changeKey: 'Changer le mot de passe clé', changeKey: 'Changer le mot de passe clé',
delayMessage: 'La génération de clé peut prendre plusieurs minutes.',
}, },
{ {
visibleRegistry: 'Visible en el Registro', visibleRegistry: 'Visible en el Registro',
edit: 'Editar', edit: 'Editar',
enableNotifications: 'Permitir Notificaciones', enableNotifications: 'Notificaciones Push',
sealedTopics: 'Temas Protegidos', sealedTopics: 'Temas Protegidos',
colorMode: 'Modo de Color', colorMode: 'Modo de Color',
hourMode: 'Hora', hourMode: 'Hora',
@ -138,11 +140,12 @@ const Strings = [
changePassword: 'Cambiar la contraseña de la clave de seguridad.', changePassword: 'Cambiar la contraseña de la clave de seguridad.',
update: 'Actualizar', update: 'Actualizar',
changeKey: 'Cambiar clave Contraseña', changeKey: 'Cambiar clave Contraseña',
delayMessage: 'La generación de claves puede tardar varios minutos.',
}, },
{ {
visibleRegistry: 'Sichtbar in der Registrierung', visibleRegistry: 'Sichtbar in der Registrierung',
edit: 'Bearbeiten', edit: 'Bearbeiten',
enableNotifications: 'Benachrichtigungen aktivieren', enableNotifications: 'Mitteilungen',
sealedTopics: 'Gesicherte Themen', sealedTopics: 'Gesicherte Themen',
colorMode: 'Farmodus', colorMode: 'Farmodus',
hourMode: 'Stunde', hourMode: 'Stunde',
@ -184,6 +187,7 @@ const Strings = [
changePassword: 'Ändern Sie das Passwort des Sicherheitsschlüssels', changePassword: 'Ändern Sie das Passwort des Sicherheitsschlüssels',
update: 'Aktualisieren', update: 'Aktualisieren',
changeKey: 'Schlüsselpasswort ändern', changeKey: 'Schlüsselpasswort ändern',
delayMessage: 'Die Schlüsselgenerierung kann mehrere Minuten dauern.',
} }
]; ];

View File

@ -1,3 +1,4 @@
import { useState } from 'react';
import { ActivityIndicator, KeyboardAvoidingView, Modal, ScrollView, View, Switch, Text, TextInput, TouchableOpacity, Alert } from 'react-native'; import { ActivityIndicator, KeyboardAvoidingView, Modal, ScrollView, View, Switch, Text, TextInput, TouchableOpacity, Alert } from 'react-native';
import { SafeAreaProvider, SafeAreaView } from 'react-native-safe-area-context'; import { SafeAreaProvider, SafeAreaView } from 'react-native-safe-area-context';
import { styles } from './Settings.styled'; import { styles } from './Settings.styled';
@ -7,21 +8,26 @@ import Colors from 'constants/Colors';
export function Settings() { export function Settings() {
const [ busy, setBusy ] = useState(false);
const { state, actions } = useSettings(); const { state, actions } = useSettings();
const saveSeal = async () => { const sealAction = async (method, name) => {
try { if (!busy) {
await actions.saveSeal(); try {
actions.hideEditSeal(); setBusy(true);
await method();
actions.hideEditSeal();
}
catch (err) {
console.log(err);
Alert.alert(
`Failed to ${name} Key`,
'Please try again.',
);
}
setBusy(false);
} }
catch (err) { };
console.log(err);
Alert.alert(
'Failed to Update Topic Sealing',
'Please try again.',
)
}
}
return ( return (
<ScrollView style={styles.content}> <ScrollView style={styles.content}>
@ -33,10 +39,8 @@ export function Settings() {
<View style={styles.icon}> <View style={styles.icon}>
<MatIcons name="bell-outline" size={20} color={Colors.linkText} /> <MatIcons name="bell-outline" size={20} color={Colors.linkText} />
</View> </View>
<View style={styles.option}> <View style={styles.optionControl}>
<Text style={styles.optionLink}>{ state.strings.enableNotifications }</Text> <Text style={styles.optionLink}>{ state.strings.enableNotifications }</Text>
</View>
<View style={styles.control}>
<Switch style={styles.notifications} trackColor={styles.track}/> <Switch style={styles.notifications} trackColor={styles.track}/>
</View> </View>
</TouchableOpacity> </TouchableOpacity>
@ -45,7 +49,7 @@ export function Settings() {
<View style={styles.icon}> <View style={styles.icon}>
<MatIcons name="lock-outline" size={20} color={Colors.linkText} /> <MatIcons name="lock-outline" size={20} color={Colors.linkText} />
</View> </View>
<View style={styles.option}> <View style={styles.optionControl}>
{ state.sealEnabled && ( { state.sealEnabled && (
<Text style={styles.optionLink}>{ state.strings.manageTopics }</Text> <Text style={styles.optionLink}>{ state.strings.manageTopics }</Text>
)} )}
@ -53,7 +57,6 @@ export function Settings() {
<Text style={styles.optionLink}>{ state.strings.enableTopics }</Text> <Text style={styles.optionLink}>{ state.strings.enableTopics }</Text>
)} )}
</View> </View>
<View style={styles.control} />
</TouchableOpacity> </TouchableOpacity>
</View> </View>
@ -200,11 +203,12 @@ export function Settings() {
<KeyboardAvoidingView behavior="height" style={styles.modalOverlay}> <KeyboardAvoidingView behavior="height" style={styles.modalOverlay}>
<View style={styles.modalContainer}> <View style={styles.modalContainer}>
<View style={styles.modalClose}> <View style={styles.modalClose}>
<TouchableOpacity activeOpacity={1} onPress={actions.hideEditSeal}> <TouchableOpacity style={styles.closeButton} activeOpacity={1} onPress={actions.hideEditSeal}>
<MatIcons name="close" size={20} color={Colors.descriptionText} /> <MatIcons name="close" size={20} color={Colors.descriptionText} />
</TouchableOpacity> </TouchableOpacity>
</View> </View>
<Text style={styles.modalHeader}>{ state.strings.sealedTopics }</Text> <Text style={styles.modalHeader}>{ state.strings.sealedTopics }</Text>
<ActivityIndicator style={styles.modalBusy} animating={busy} color={Colors.primary} />
{ !state.sealEnabled && ( { !state.sealEnabled && (
<> <>
<Text style={styles.modalDescription}>{ state.strings.sealUnset }</Text> <Text style={styles.modalDescription}>{ state.strings.sealUnset }</Text>
@ -239,7 +243,7 @@ export function Settings() {
)} )}
</View> </View>
{ state.sealPassword === state.sealConfirm && state.sealPassword && ( { state.sealPassword === state.sealConfirm && state.sealPassword && (
<TouchableOpacity style={styles.enabledButton} activeOpacity={1} onPress={actions.generateKey}> <TouchableOpacity style={styles.enabledButton} activeOpacity={1} onPress={() => sealAction(actions.generateKey, 'Generate')}>
<Text style={styles.enabledButtonText}>{ state.strings.generate }</Text> <Text style={styles.enabledButtonText}>{ state.strings.generate }</Text>
</TouchableOpacity> </TouchableOpacity>
)} )}
@ -248,14 +252,135 @@ export function Settings() {
<Text style={styles.disabledButtonText}>{ state.strings.generate }</Text> <Text style={styles.disabledButtonText}>{ state.strings.generate }</Text>
</View> </View>
)} )}
<Text style={styles.delayMessage}>{ state.strings.delayMessage }</Text>
</> </>
)} )}
{ state.sealEnabled && !state.sealUnlocked && ( { state.sealEnabled && !state.sealUnlocked && !state.sealRemove && (
<Text style={styles.modalDescription}>{ state.strings.sealLocked }</Text> <>
<Text style={styles.modalDescription}>{ state.strings.sealLocked }</Text>
<View style={styles.modalInput}>
<TextInput style={styles.inputText} value={state.sealPassword} onChangeText={actions.setSealPassword}
autoCapitalize={'none'} secureTextEntry={state.hidePassword} placeholder={state.strings.password}
placeholderTextColor={Colors.inputPlaceholder} />
{ state.hidePassword && (
<TouchableOpacity style={styles.inputVisibility} activeOpacity={1} onPress={actions.showPassword}>
<MatIcons name="eye-outline" size={16} color={Colors.inputPlaceholder} />
</TouchableOpacity>
)}
{ !state.hidePassword && (
<TouchableOpacity style={styles.inputVisibility} activeOpacity={1} onPress={actions.hidePassword}>
<MatIcons name="eye-off-outline" size={16} color={Colors.inputPlaceholder} />
</TouchableOpacity>
)}
</View>
{ state.sealPassword && (
<TouchableOpacity style={styles.enabledButton} activeOpacity={1} onPress={() => sealAction(actions.unlockKey, 'Unlock')}>
<Text style={styles.enabledButtonText}>{ state.strings.unlock }</Text>
</TouchableOpacity>
)}
{ !state.sealPassword && (
<View style={styles.disabledButton}>
<Text style={styles.disabledButtonText}>{ state.strings.unlock }</Text>
</View>
)}
<TouchableOpacity activeOpacity={1} onPress={actions.showSealRemove}>
<Text style={styles.dangerText}>{ state.strings.removeSeal }</Text>
</TouchableOpacity>
</>
)} )}
{ state.sealEnabled && state.sealUnlocked && ( { state.sealEnabled && state.sealUnlocked && !state.sealRemove && !state.sealUpdate && (
<> <>
<Text style={styles.modalDescription}>{ state.strings.sealUnlocked }</Text> <Text style={styles.modalDescription}>{ state.strings.sealUnlocked }</Text>
<TouchableOpacity style={styles.enabledButton} activeOpacity={1} onPress={() => sealAction(actions.disableKey, 'Disable')}>
<Text style={styles.enabledButtonText}>{ state.strings.disable }</Text>
</TouchableOpacity>
<TouchableOpacity activeOpacity={1} onPress={actions.showSealUpdate}>
<Text style={styles.modeText}>{ state.strings.changeKey }</Text>
</TouchableOpacity>
<TouchableOpacity activeOpacity={1} onPress={actions.showSealRemove}>
<Text style={styles.dangerText}>{ state.strings.removeSeal }</Text>
</TouchableOpacity>
</>
)}
{ state.sealEnabled && state.sealRemove && (
<>
<Text style={styles.modalDescription}>{ state.strings.sealDelete }</Text>
<View style={styles.modalInput}>
<TextInput style={styles.inputText} value={state.sealDelete} onChangeText={actions.setSealDelete}
autoCapitalize={'none'} placeholder={state.strings.typeDelete}
placeholderTextColor={Colors.inputPlaceholder} />
</View>
{ state.sealDelete === state.strings.deleteKey && (
<TouchableOpacity style={styles.dangerButton} activeOpacity={1} onPress={() => sealAction(actions.removeKey, 'Remove')}>
<Text style={styles.dangerButtonText}>{ state.strings.delete }</Text>
</TouchableOpacity>
)}
{ state.sealDelete !== state.strings.deleteKey && (
<View style={styles.disabledButton}>
<Text style={styles.disabledButtonText}>{ state.strings.delete }</Text>
</View>
)}
<TouchableOpacity activeOpacity={1} onPress={actions.hideSealRemove}>
{ state.sealUnlocked && (
<Text style={styles.modeText}>{ state.strings.disableSeal }</Text>
)}
{ !state.sealUnlocked && (
<Text style={styles.modeText}>{ state.strings.unlockSeal }</Text>
)}
</TouchableOpacity>
</>
)}
{ state.sealEnabled && state.sealUnlocked && state.sealUpdate && (
<>
<Text style={styles.modalDescription}>{ state.strings.changePassword }</Text>
<View style={styles.modalInput}>
<TextInput style={styles.inputText} value={state.sealPassword} onChangeText={actions.setSealPassword}
autoCapitalize={'none'} secureTextEntry={state.hidePassword} placeholder={state.strings.password}
placeholderTextColor={Colors.inputPlaceholder} />
{ state.hidePassword && (
<TouchableOpacity style={styles.inputVisibility} activeOpacity={1} onPress={actions.showPassword}>
<MatIcons name="eye-outline" size={16} color={Colors.inputPlaceholder} />
</TouchableOpacity>
)}
{ !state.hidePassword && (
<TouchableOpacity style={styles.inputVisibility} activeOpacity={1} onPress={actions.hidePassword}>
<MatIcons name="eye-off-outline" size={16} color={Colors.inputPlaceholder} />
</TouchableOpacity>
)}
</View>
<View style={styles.modalInput}>
<TextInput style={styles.inputText} value={state.sealConfirm} onChangeText={actions.setSealConfirm}
autoCapitalize={'none'} secureTextEntry={state.hideConfirm} placeholder={state.strings.confirmPassword}
placeholderTextColor={Colors.inputPlaceholder} />
{ state.hideConfirm && (
<TouchableOpacity style={styles.inputVisibility} activeOpacity={1} onPress={actions.showConfirm}>
<MatIcons name="eye-outline" size={16} color={Colors.inputPlaceholder} />
</TouchableOpacity>
)}
{ !state.hideConfirm && (
<TouchableOpacity style={styles.inputVisibility} activeOpacity={1} onPress={actions.showConfirm}>
<MatIcons name="eye-off-outline" size={16} color={Colors.inputPlaceholder} />
</TouchableOpacity>
)}
</View>
{ state.sealPassword === state.sealConfirm && state.sealPassword && (
<TouchableOpacity style={styles.enabledButton} activeOpacity={1} onPress={() => sealAction(actions.updateKey, 'Update')}>
<Text style={styles.enabledButtonText}>{ state.strings.update }</Text>
</TouchableOpacity>
)}
{ (state.sealPassword !== state.sealConfirm || !state.sealPassword) && (
<View style={styles.disabledButton}>
<Text style={styles.disabledButtonText}>{ state.strings.update }</Text>
</View>
)}
<TouchableOpacity activeOpacity={1} onPress={actions.hideSealUpdate}>
{ state.sealUnlocked && (
<Text style={styles.modeText}>{ state.strings.disableSeal }</Text>
)}
{ !state.sealUnlocked && (
<Text style={styles.modeText}>{ state.strings.unlockSeal }</Text>
)}
</TouchableOpacity>
</> </>
)} )}
</View> </View>

View File

@ -76,8 +76,8 @@ export const styles = StyleSheet.create({
alignItems: 'center', alignItems: 'center',
}, },
control: { control: {
flex: 2, flex: 4,
alignItems: 'center', display: 'flex',
}, },
labelText: { labelText: {
fontSize: 14, fontSize: 14,
@ -129,7 +129,6 @@ export const styles = StyleSheet.create({
}, },
modalHeader: { modalHeader: {
fontSize: 18, fontSize: 18,
paddingBottom: 16,
paddingTop: 16, paddingTop: 16,
color: Colors.text, color: Colors.text,
fontFamily: 'Roboto', fontFamily: 'Roboto',
@ -139,17 +138,25 @@ export const styles = StyleSheet.create({
width: '100%', width: '100%',
display: 'flex', display: 'flex',
alignItems: 'flex-end', alignItems: 'flex-end',
paddingRight: 8, },
paddingTop: 8, closeButton: {
padding: 12,
},
modalBusy: {
padding: 8,
}, },
modalDescription: { modalDescription: {
fontSize: 14, fontSize: 14,
color: Colors.descriptionText, color: Colors.descriptionText,
paddingTop: 16,
paddingLeft: 16, paddingLeft: 16,
paddingRight: 16, paddingRight: 16,
paddingBottom: 16, paddingBottom: 16,
}, },
delayMessage: {
fontSize: 12,
color: Colors.descriptionText,
paddingBottom: 16,
},
modalInput: { modalInput: {
marginRight: 32, marginRight: 32,
marginLeft: 32, marginLeft: 32,
@ -158,12 +165,21 @@ export const styles = StyleSheet.create({
justifyContent: 'center', justifyContent: 'center',
flexDirection: 'row', flexDirection: 'row',
}, },
modeText: {
fontSize: 14,
paddingBottom: 16,
color: Colors.linkText,
fontFamily: 'Roboto',
},
dangerText: {
fontSize: 14,
paddingBottom: 16,
color: Colors.dangerText,
fontFamily: 'Roboto',
},
inputText: { inputText: {
flex: 1, flex: 1,
paddingLeft: 8, padding: 8,
paddingRight: 8,
paddingTop: 4,
paddingBottom: 4,
borderRadius: 4, borderRadius: 4,
margin: 4, margin: 4,
backgroundColor: Colors.inputBase, backgroundColor: Colors.inputBase,
@ -200,5 +216,19 @@ export const styles = StyleSheet.create({
color: Colors.disabledButtonText, color: Colors.disabledButtonText,
fontFamily: 'Roboto', fontFamily: 'Roboto',
}, },
dangerButton: {
marginTop: 32,
marginBottom: 16,
paddingTop: 8,
paddingBottom: 8,
paddingLeft: 32,
paddingRight: 32,
borderRadius: 4,
backgroundColor: Colors.dangerButton,
},
dangerButtonText: {
color: Colors.dangerButtonText,
fontFamily: 'Roboto',
},
}); });

View File

@ -19,8 +19,11 @@ export function useSettings() {
sealUnlocked: false, sealUnlocked: false,
sealPassword: null, sealPassword: null,
sealConfirm: null, sealConfirm: null,
sealDelete: null,
hideConfirm: true, hideConfirm: true,
hidePassword: true, hidePassword: true,
sealRemove: false,
sealUpdate: false,
}); });
const updateState = (value) => { const updateState = (value) => {
@ -40,26 +43,26 @@ export function useSettings() {
updateState({ sealable, seal, sealKey, sealEnabled, sealUnlocked }); updateState({ sealable, seal, sealKey, sealEnabled, sealUnlocked });
}, [account.state]); }, [account.state]);
const unlock = async () => { const unlockKey = async () => {
const sealKey = unlockSeal(state.seal, state.sealUnlock); const sealKey = unlockSeal(state.seal, state.sealPassword);
await account.actions.unlockAccountSeal(sealKey); await account.actions.unlockAccountSeal(sealKey);
}; };
const forget = async () => { const disableKey = async () => {
await account.actions.unlockAccountSeal({}); await account.actions.unlockAccountSeal({});
} }
const update = async () => { const updateKey = async () => {
const updated = updateSeal(state.seal, state.sealKey, state.sealPassword); const updated = updateSeal(state.seal, state.sealKey, state.sealPassword);
await account.actions.setAccountSeal(updated.seal, updated.sealKey); await account.actions.setAccountSeal(updated.seal, updated.sealKey);
} }
const enable = async () => { const generateKey = async () => {
const created = await generateSeal(state.sealPassword); const created = await generateSeal(state.sealPassword);
await account.actions.setAccountSeal(created.seal, created.sealKey); await account.actions.setAccountSeal(created.seal, created.sealKey);
} }
const disable = async () => { const removeKey = async () => {
await account.actions.setAccountSeal({}, {}); await account.actions.setAccountSeal({}, {});
} }
@ -73,17 +76,33 @@ export function useSettings() {
await profile.actions.setMonthLast(flag); await profile.actions.setMonthLast(flag);
}, },
showEditSeal: () => { showEditSeal: () => {
updateState({ editSeal: true, sealPassword: null, sealConfirm: null }); updateState({ editSeal: true, sealPassword: null, sealConfirm: null, hidePassword: true, hideConfirm: true,
sealDelete: null, sealRemove: false, sealUpdate: false });
}, },
hideEditSeal: () => { hideEditSeal: () => {
updateState({ editSeal: false }); updateState({ editSeal: false });
}, },
showSealRemove: () => {
updateState({ sealRemove: true });
},
hideSealRemove: () => {
updateState({ sealRemove: false });
},
showSealUpdate: () => {
updateState({ sealUpdate: true });
},
hideSealUpdate: () => {
updateState({ sealUpdate: false });
},
setSealPassword: (sealPassword) => { setSealPassword: (sealPassword) => {
updateState({ sealPassword }); updateState({ sealPassword });
}, },
setSealConfirm: (sealConfirm) => { setSealConfirm: (sealConfirm) => {
updateState({ sealConfirm }); updateState({ sealConfirm });
}, },
setSealDelete: (sealDelete) => {
updateState({ sealDelete });
},
showPassword: () => { showPassword: () => {
updateState({ hidePassword: false }); updateState({ hidePassword: false });
}, },
@ -96,8 +115,20 @@ export function useSettings() {
hideConfirm: () => { hideConfirm: () => {
updateState({ hideConfirm: true }); updateState({ hideConfirm: true });
}, },
generateKey: () => { generateKey: async () => {
console.log("GENERATE KEY"); await generateKey();
},
disableKey: async () => {
await disableKey();
},
unlockKey: async () => {
await unlockKey();
},
updateKey: async () => {
await updateKey();
},
removeKey: async () => {
await removeKey();
}, },
}; };