From 46fe1ceeb66c0fab4db8e0dc9098d5e8a9f3261d Mon Sep 17 00:00:00 2001 From: Tom Hacohen Date: Tue, 21 May 2019 16:56:32 +0100 Subject: [PATCH] Gracefully handle wrong encryption passwords. Until now we just showed integrity error which could be one of many issues. Now we show an explicit error message and only clear the encryption password cache rather than the whole cache. --- src/SyncGate.tsx | 11 ++++++++ src/api/EteSync.ts | 8 ++++++ src/components/ErrorBoundary.tsx | 47 ++++++++++++++++++++------------ src/store/actions.ts | 7 +++++ src/store/reducers.ts | 3 ++ 5 files changed, 58 insertions(+), 18 deletions(-) diff --git a/src/SyncGate.tsx b/src/SyncGate.tsx index e1df568..4842c43 100644 --- a/src/SyncGate.tsx +++ b/src/SyncGate.tsx @@ -54,6 +54,17 @@ const syncInfoSelector = createSelector( (etesync, journals, entries, userInfo) => { const derived = etesync.encryptionKey; let asymmetricCryptoManager: EteSync.AsymmetricCryptoManager; + try { + const userInfoCryptoManager = new EteSync.CryptoManager(etesync.encryptionKey, 'userInfo'); + userInfo.verify(userInfoCryptoManager); + } catch (error) { + if (error instanceof EteSync.IntegrityError) { + throw new EteSync.EncryptionPasswordError(error.message); + } else { + throw error; + } + } + return journals.reduce( (ret, journal) => { const journalEntries = entries.get(journal.uid); diff --git a/src/api/EteSync.ts b/src/api/EteSync.ts index 9663a8d..33bac81 100644 --- a/src/api/EteSync.ts +++ b/src/api/EteSync.ts @@ -32,6 +32,14 @@ export class IntegrityError extends ExtendableError { } } +export class EncryptionPasswordError extends ExtendableError { + constructor(message: any) { + super(message); + Object.setPrototypeOf(this, EncryptionPasswordError.prototype); + this.name = this.constructor.name; + } +} + // FIXME: Make secure + types function CastJson(json: any, to: any) { return Object.assign(to, json); diff --git a/src/components/ErrorBoundary.tsx b/src/components/ErrorBoundary.tsx index 4d84667..9c5cc6c 100644 --- a/src/components/ErrorBoundary.tsx +++ b/src/components/ErrorBoundary.tsx @@ -1,8 +1,9 @@ import * as React from 'react'; -import { persistor } from '../store'; +import { store, persistor } from '../store'; +import { resetKey } from '../store/actions'; -import { IntegrityError } from '../api/EteSync'; +import { EncryptionPasswordError, IntegrityError } from '../api/EteSync'; import PrettyError from '../widgets/PrettyError'; class ErrorBoundary extends React.Component { @@ -16,7 +17,9 @@ class ErrorBoundary extends React.Component { } public componentDidCatch(error: Error, info: any) { - if (error instanceof IntegrityError) { + if (error instanceof EncryptionPasswordError) { + store.dispatch(resetKey()); + } else if (error instanceof IntegrityError) { persistor.purge(); } @@ -25,21 +28,29 @@ class ErrorBoundary extends React.Component { public render() { const { error } = this.state; - if (error && error instanceof IntegrityError) { - return ( -
-

Integrity Error

-

- This probably means you put in the wrong encryption password. -

-

- Please log out from the menu, refresh the page and try again. -

-
-            {error.message}
-          
-
- ); + if (error) { + if (error instanceof EncryptionPasswordError) { + return ( +
+

Wrong Encryption Password

+

+ It looks like you've entered the wrong encryption password, please refresh the page and try again. +

+
+ ); + } else if (error instanceof IntegrityError) { + return ( +
+

Integrity Error

+

+ Please log out from the menu, refresh the page and try again, and if the problem persists, contact support. +

+
+                {error.message}
+            
+
+ ); + } } if (error) { diff --git a/src/store/actions.ts b/src/store/actions.ts index 327c125..4a54087 100644 --- a/src/store/actions.ts +++ b/src/store/actions.ts @@ -36,6 +36,13 @@ export const { deriveKey } = createActions({ }, }); +export const resetKey = createAction( + 'RESET_KEY', + () => { + return null; + } +); + export const login = (username: string, password: string, encryptionPassword: string, server: string) => { return (dispatch: any) => { dispatch(fetchCredentials(username, password, server)).then(() => diff --git a/src/store/reducers.ts b/src/store/reducers.ts index 9957883..65ad14b 100644 --- a/src/store/reducers.ts +++ b/src/store/reducers.ts @@ -84,6 +84,9 @@ export const encryptionKeyReducer = handleActions( [actions.deriveKey.toString()]: (state: {key: string | null}, action: any) => ( {key: action.payload} ), + [actions.resetKey.toString()]: (state: {key: string | null}, action: any) => ( + {key: null} + ), [actions.logout.toString()]: (state: {key: string | null}, action: any) => { return {out: true, key: null}; },