From f4ad6c9a9f1621f06907ce6fe9e064d88ae175ad Mon Sep 17 00:00:00 2001 From: Roland Osborne Date: Tue, 29 Aug 2023 12:04:47 -0700 Subject: [PATCH] wrapped up first pass of sealing wizard --- app/mobile/src/constants/Colors.js | 6 + app/mobile/src/constants/Strings.js | 16 +- app/mobile/src/session/settings/Settings.jsx | 169 +++++++++++++++--- .../src/session/settings/Settings.styled.js | 50 ++++-- .../src/session/settings/useSettings.hook.js | 49 ++++- 5 files changed, 243 insertions(+), 47 deletions(-) diff --git a/app/mobile/src/constants/Colors.js b/app/mobile/src/constants/Colors.js index 50a44248..fcc23bc1 100644 --- a/app/mobile/src/constants/Colors.js +++ b/app/mobile/src/constants/Colors.js @@ -23,6 +23,8 @@ const LightColors = { primaryButtonText: '#ffffff', disabledButton: '#dddddd', disabledButtonText: '#aaaaaa', + dangerButton: '#ff5555', + dangerButtonText: '#ffffff', inputBase: '#eeeeee', inputPlaceholder: '#888888', inputText: '#444444', @@ -64,6 +66,8 @@ const DarkColors = { primaryButtonText: '#ffffff', disabledButton: '#aaaaaa', disabledButtonText: '#888888', + dangerButton: '#ff888888', + dangerButtonText: '#ffffff', inputBase: '#ffffff', inputPlaceholder: '#888888', inputText: '#444444', @@ -109,6 +113,8 @@ export const Colors = { primaryButtonText: getColor('primaryButtonText'), disabledButton: getColor('disabledButton'), disabledButtonText: getColor('disabledButtonText'), + dangerButton: getColor('dangerButton'), + dangerButtonText: getColor('dangerButtonText'), inputBase: getColor('inputBase'), inputPlaceholder: getColor('inputPlaceholder'), inputText: getColor('inputText'), diff --git a/app/mobile/src/constants/Strings.js b/app/mobile/src/constants/Strings.js index fecd7e80..e538a405 100644 --- a/app/mobile/src/constants/Strings.js +++ b/app/mobile/src/constants/Strings.js @@ -4,7 +4,7 @@ const Strings = [ { visibleRegistry: 'Visible in Registry', edit: 'Edit', - enableNotifications: 'Enable Notifications', + enableNotifications: 'Push Notifications', sealedTopics: 'Sealed Topics', colorMode: 'Color Mode', hourMode: 'Hour', @@ -27,8 +27,8 @@ const Strings = [ monthEnd: 'dd/mm', 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.', - sealLocked: 'Unlock the sealing key to enable end-to-end encrypted topics on this device.', + 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 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.', password: 'Password', confirmPassword: 'Confirm Password', @@ -46,11 +46,12 @@ const Strings = [ changePassword: 'Change sealing key password.', update: 'Update', changeKey: 'Change Key Password', + delayMessage: 'Key generation can take several minutes.', }, { visibleRegistry: 'Visible dans le Registre', edit: 'Modifier', - enableNotifications: 'Activer les Notifications', + enableNotifications: 'Notifications Push', sealedTopics: 'Sujets Sécurisés', colorMode: 'Mode de Couleur', hourMode: 'Heure', @@ -92,11 +93,12 @@ const Strings = [ changePassword: 'Changez le mot de passe de la clé de sécurité.', update: 'Mise à jour', changeKey: 'Changer le mot de passe clé', + delayMessage: 'La génération de clé peut prendre plusieurs minutes.', }, { visibleRegistry: 'Visible en el Registro', edit: 'Editar', - enableNotifications: 'Permitir Notificaciones', + enableNotifications: 'Notificaciones Push', sealedTopics: 'Temas Protegidos', colorMode: 'Modo de Color', hourMode: 'Hora', @@ -138,11 +140,12 @@ const Strings = [ changePassword: 'Cambiar la contraseña de la clave de seguridad.', update: 'Actualizar', changeKey: 'Cambiar clave Contraseña', + delayMessage: 'La generación de claves puede tardar varios minutos.', }, { visibleRegistry: 'Sichtbar in der Registrierung', edit: 'Bearbeiten', - enableNotifications: 'Benachrichtigungen aktivieren', + enableNotifications: 'Mitteilungen', sealedTopics: 'Gesicherte Themen', colorMode: 'Farmodus', hourMode: 'Stunde', @@ -184,6 +187,7 @@ const Strings = [ changePassword: 'Ändern Sie das Passwort des Sicherheitsschlüssels', update: 'Aktualisieren', changeKey: 'Schlüsselpasswort ändern', + delayMessage: 'Die Schlüsselgenerierung kann mehrere Minuten dauern.', } ]; diff --git a/app/mobile/src/session/settings/Settings.jsx b/app/mobile/src/session/settings/Settings.jsx index 72ed8e39..0b3b9ad2 100644 --- a/app/mobile/src/session/settings/Settings.jsx +++ b/app/mobile/src/session/settings/Settings.jsx @@ -1,3 +1,4 @@ +import { useState } from 'react'; import { ActivityIndicator, KeyboardAvoidingView, Modal, ScrollView, View, Switch, Text, TextInput, TouchableOpacity, Alert } from 'react-native'; import { SafeAreaProvider, SafeAreaView } from 'react-native-safe-area-context'; import { styles } from './Settings.styled'; @@ -7,21 +8,26 @@ import Colors from 'constants/Colors'; export function Settings() { + const [ busy, setBusy ] = useState(false); const { state, actions } = useSettings(); - const saveSeal = async () => { - try { - await actions.saveSeal(); - actions.hideEditSeal(); + const sealAction = async (method, name) => { + if (!busy) { + try { + 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 ( @@ -33,10 +39,8 @@ export function Settings() { - + { state.strings.enableNotifications } - - @@ -45,7 +49,7 @@ export function Settings() { - + { state.sealEnabled && ( { state.strings.manageTopics } )} @@ -53,7 +57,6 @@ export function Settings() { { state.strings.enableTopics } )} - @@ -200,11 +203,12 @@ export function Settings() { - + { state.strings.sealedTopics } + { !state.sealEnabled && ( <> { state.strings.sealUnset } @@ -239,7 +243,7 @@ export function Settings() { )} { state.sealPassword === state.sealConfirm && state.sealPassword && ( - + sealAction(actions.generateKey, 'Generate')}> { state.strings.generate } )} @@ -248,14 +252,135 @@ export function Settings() { { state.strings.generate } )} + { state.strings.delayMessage } )} - { state.sealEnabled && !state.sealUnlocked && ( - { state.strings.sealLocked } + { state.sealEnabled && !state.sealUnlocked && !state.sealRemove && ( + <> + { state.strings.sealLocked } + + + { state.hidePassword && ( + + + + )} + { !state.hidePassword && ( + + + + )} + + { state.sealPassword && ( + sealAction(actions.unlockKey, 'Unlock')}> + { state.strings.unlock } + + )} + { !state.sealPassword && ( + + { state.strings.unlock } + + )} + + { state.strings.removeSeal } + + )} - { state.sealEnabled && state.sealUnlocked && ( + { state.sealEnabled && state.sealUnlocked && !state.sealRemove && !state.sealUpdate && ( <> { state.strings.sealUnlocked } + sealAction(actions.disableKey, 'Disable')}> + { state.strings.disable } + + + { state.strings.changeKey } + + + { state.strings.removeSeal } + + + )} + { state.sealEnabled && state.sealRemove && ( + <> + { state.strings.sealDelete } + + + + { state.sealDelete === state.strings.deleteKey && ( + sealAction(actions.removeKey, 'Remove')}> + { state.strings.delete } + + )} + { state.sealDelete !== state.strings.deleteKey && ( + + { state.strings.delete } + + )} + + { state.sealUnlocked && ( + { state.strings.disableSeal } + )} + { !state.sealUnlocked && ( + { state.strings.unlockSeal } + )} + + + )} + { state.sealEnabled && state.sealUnlocked && state.sealUpdate && ( + <> + { state.strings.changePassword } + + + { state.hidePassword && ( + + + + )} + { !state.hidePassword && ( + + + + )} + + + + { state.hideConfirm && ( + + + + )} + { !state.hideConfirm && ( + + + + )} + + { state.sealPassword === state.sealConfirm && state.sealPassword && ( + sealAction(actions.updateKey, 'Update')}> + { state.strings.update } + + )} + { (state.sealPassword !== state.sealConfirm || !state.sealPassword) && ( + + { state.strings.update } + + )} + + { state.sealUnlocked && ( + { state.strings.disableSeal } + )} + { !state.sealUnlocked && ( + { state.strings.unlockSeal } + )} + )} diff --git a/app/mobile/src/session/settings/Settings.styled.js b/app/mobile/src/session/settings/Settings.styled.js index 548980ce..0dac4c4a 100644 --- a/app/mobile/src/session/settings/Settings.styled.js +++ b/app/mobile/src/session/settings/Settings.styled.js @@ -76,8 +76,8 @@ export const styles = StyleSheet.create({ alignItems: 'center', }, control: { - flex: 2, - alignItems: 'center', + flex: 4, + display: 'flex', }, labelText: { fontSize: 14, @@ -129,7 +129,6 @@ export const styles = StyleSheet.create({ }, modalHeader: { fontSize: 18, - paddingBottom: 16, paddingTop: 16, color: Colors.text, fontFamily: 'Roboto', @@ -139,17 +138,25 @@ export const styles = StyleSheet.create({ width: '100%', display: 'flex', alignItems: 'flex-end', - paddingRight: 8, - paddingTop: 8, + }, + closeButton: { + padding: 12, + }, + modalBusy: { + padding: 8, }, modalDescription: { fontSize: 14, color: Colors.descriptionText, - paddingTop: 16, paddingLeft: 16, paddingRight: 16, paddingBottom: 16, }, + delayMessage: { + fontSize: 12, + color: Colors.descriptionText, + paddingBottom: 16, + }, modalInput: { marginRight: 32, marginLeft: 32, @@ -158,12 +165,21 @@ export const styles = StyleSheet.create({ justifyContent: 'center', flexDirection: 'row', }, + modeText: { + fontSize: 14, + paddingBottom: 16, + color: Colors.linkText, + fontFamily: 'Roboto', + }, + dangerText: { + fontSize: 14, + paddingBottom: 16, + color: Colors.dangerText, + fontFamily: 'Roboto', + }, inputText: { flex: 1, - paddingLeft: 8, - paddingRight: 8, - paddingTop: 4, - paddingBottom: 4, + padding: 8, borderRadius: 4, margin: 4, backgroundColor: Colors.inputBase, @@ -200,5 +216,19 @@ export const styles = StyleSheet.create({ color: Colors.disabledButtonText, 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', + }, }); diff --git a/app/mobile/src/session/settings/useSettings.hook.js b/app/mobile/src/session/settings/useSettings.hook.js index 7efc6934..58e3edac 100644 --- a/app/mobile/src/session/settings/useSettings.hook.js +++ b/app/mobile/src/session/settings/useSettings.hook.js @@ -19,8 +19,11 @@ export function useSettings() { sealUnlocked: false, sealPassword: null, sealConfirm: null, + sealDelete: null, hideConfirm: true, hidePassword: true, + sealRemove: false, + sealUpdate: false, }); const updateState = (value) => { @@ -40,26 +43,26 @@ export function useSettings() { updateState({ sealable, seal, sealKey, sealEnabled, sealUnlocked }); }, [account.state]); - const unlock = async () => { - const sealKey = unlockSeal(state.seal, state.sealUnlock); + const unlockKey = async () => { + const sealKey = unlockSeal(state.seal, state.sealPassword); await account.actions.unlockAccountSeal(sealKey); }; - const forget = async () => { + const disableKey = async () => { await account.actions.unlockAccountSeal({}); } - const update = async () => { + const updateKey = async () => { const updated = updateSeal(state.seal, state.sealKey, state.sealPassword); await account.actions.setAccountSeal(updated.seal, updated.sealKey); } - const enable = async () => { + const generateKey = async () => { const created = await generateSeal(state.sealPassword); await account.actions.setAccountSeal(created.seal, created.sealKey); } - const disable = async () => { + const removeKey = async () => { await account.actions.setAccountSeal({}, {}); } @@ -73,17 +76,33 @@ export function useSettings() { await profile.actions.setMonthLast(flag); }, 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: () => { updateState({ editSeal: false }); }, + showSealRemove: () => { + updateState({ sealRemove: true }); + }, + hideSealRemove: () => { + updateState({ sealRemove: false }); + }, + showSealUpdate: () => { + updateState({ sealUpdate: true }); + }, + hideSealUpdate: () => { + updateState({ sealUpdate: false }); + }, setSealPassword: (sealPassword) => { updateState({ sealPassword }); }, setSealConfirm: (sealConfirm) => { updateState({ sealConfirm }); }, + setSealDelete: (sealDelete) => { + updateState({ sealDelete }); + }, showPassword: () => { updateState({ hidePassword: false }); }, @@ -96,8 +115,20 @@ export function useSettings() { hideConfirm: () => { updateState({ hideConfirm: true }); }, - generateKey: () => { - console.log("GENERATE KEY"); + generateKey: async () => { + await generateKey(); + }, + disableKey: async () => { + await disableKey(); + }, + unlockKey: async () => { + await unlockKey(); + }, + updateKey: async () => { + await updateKey(); + }, + removeKey: async () => { + await removeKey(); }, };